//自定義線程池
private static ThreadPoolExecutor executor = new ThreadPoolExecutor(8,16,20, TimeUnit.SECONDS,new LinkedBlockingDeque<>(20), Executors.defaultThreadFactory(), (r, executor1) -> new Thread(r).start());
System.out.println("Main 線程名稱: "+Thread.currentThread().getName());
//runAsync 開啓一個異步任務,接受一個Runnable,可選傳入自定義線程池
CompletableFuture.runAsync(()-> System.out.println(Thread.currentThread().getName()+" CSDN——Mutou_ren CompletableFuture.runAsync"),executor);
//supplyAsync 開啓一個異步任務,接受一個supplier函數,如果不指定自定義線程池默認都是使用ForkJoinPool.commonPool線程池
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(()-> (Thread.currentThread().getName()+" CSDN——Mutou_ren CompletableFuture.supplyAsync"));
System.out.println(Thread.currentThread().getName()+" "+future1.get());
thenRun
//thenRun接受一個runnable ,無法讀取前面的結果
CompletableFuture.supplyAsync(()->{
System.out.println("thenRun前置準備睡眠");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thenRun前置睡眠結束");
return 1;
}).thenRun(()-> System.out.println("then run 執行,無法拿到前置任務的結果"));
thenAccept
//thenAccept可以接收一個consumer,能讀取到前面的結果
CompletableFuture.supplyAsync(()->{
System.out.println("thenAccept前置準備睡眠");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thenAccept前置睡眠結束");
return "thenAccept前置返回值";
}).thenAccept(e-> System.out.println("then accept 可以收到前置任務的結果爲:"+e));
thenApply
//thenApply接收一個function,可以讀取前面的結果並返回新的結果,
CompletableFuture future2 = CompletableFuture.supplyAsync(()->{
System.out.println("thenApply前置準備睡眠");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thenAccept前置睡眠結束");
return "thenApply前置返回值";
}).thenApply(e->e+" then apply 添加");
System.out.println(Thread.currentThread().getName()+future2.get());
whenComplete
CompletableFuture future3 = CompletableFuture.supplyAsync(()->{
System.out.println("thenAccept前置準備睡眠");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thenAccept前置睡眠結束");
return "future3";
});
//設置回調,t代表異常thrown
future3.whenComplete((e,t)-> System.out.println(Thread.currentThread().getName()+"whenComplete "+e));
thenCombine
//收集前面的和當前的CompletableFuture 的返回值作爲參數,傳遞給function
CompletableFuture future7 = CompletableFuture.supplyAsync(()->"then").thenCombine( CompletableFuture.supplyAsync(()->"combine"),(a,b)-> a+" "+b);
System.out.println(future7.get());
thenCompose
//前面的CompletableFuture 返回值可以作爲下一個CompletableFuture 的參數
CompletableFuture future8 = CompletableFuture.supplyAsync(()->"then").thenCompose(str -> CompletableFuture.supplyAsync(()-> str+" compose"));
System.out.println(future8.get());
allof
//模擬耗時操作
public static Integer getResult(int integer){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
return integer;
}
List<CompletableFuture<Integer>> futureList = new ArrayList(50);
for (int i=0;i<50;i++){
futureList.add(CompletableFuture.supplyAsync(()->getResult(1),executor));
}
//在另一個流上對每個future進行join操作,等價allof
List<Integer> resultList = futureList.stream().map(e -> e.join()).collect(Collectors.toList());
System.out.println(resultList.size());
//將多個future合併成一個等待
CompletableFuture all = CompletableFuture.allOf(futureList.toArray(new CompletableFuture[futureList.size()]));
//這裏返回就代表列表中所有的future全返回了
all.get();
System.out.println(futureList.stream().filter(e -> !e.isDone()).count());
anyof
List<CompletableFuture<Integer>> futureList = new ArrayList(50);
for (int i=0;i<50;i++){
futureList.add(CompletableFuture.supplyAsync(()->getResult(1),executor));
}
CompletableFuture any = CompletableFuture.anyOf(futureList.toArray(new CompletableFuture[futureList.size()]));
//這裏返回就代表列表中有future返回了
any.get();
System.out.println(futureList.stream().filter(e -> !e.isDone()).count());
原理
在CompletableFuture.supplyAsync
等方法中,實際上就是新建了一個CompletableFuture
對象,然後使用線程池運行任務並立即將這個CompletableFuture
對象返回。在線程池運行任務時,會在run後將結果通過future.complete()
或異常future.completeExceptionlly()
設置到CompletableFuture
對象中
Future.get
調用get時會判斷任務狀態是否結束,若沒有結束則構建成等待節點並park
;當任務完成進行set結果或異常set異常時,會通過finishCompletion()
將所有等待的節點線程unpark
並刪除節點,思想還是AQS那套思想