阿里自助建站平臺/網站優(yōu)化公司收費
CompletableFuture(可完成的Future)
一個可完成的Future,在我們調用他的get方法的時候,他會阻塞等待這個任務完成來獲取他的結果。
當然也可以為這個任務注冊一些回調,類似于完成時,出現(xiàn)異常時,或者執(zhí)行超時等額外處理。
使用
CompletableFuture.suppleAsync
異步執(zhí)行一個任務并返回結果
CompletableFuture.runAsync
異步執(zhí)行一個任務不返回結果
這兩方法都可以為我們快速的創(chuàng)建一個CompletableFuture對象
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName() + ":supplyAsync start");return "supplyAsync";
});CompletableFuture<String> completableFuture = CompletableFuture.runAsync(() -> {System.out.println(Thread.currentThread().getName() + ":runAsync start");return "runAsync";
});
這兩個方法都是可以有第二個參數(shù)的,也就是可以執(zhí)行線程池,這里默認是
**Fork-Join-Pool**
(一個可以將一個大任務很自然的分解為多個子任務的線程池)。
回調有哪些
方法 | 參數(shù) | 描述 |
---|---|---|
thenApply | T -> U | 對結果進行處理,并返回一個新的結果 |
thenAccpet | T -> void | 對結果進行處理,返回結果為Void |
thenCompose | T -> CompletableFuture | 對結果調用這個函數(shù)來進行處理,并返回一個新的結果 |
handle | (T,Throwable) -> U | 與thenApply類似,但是他可以處理異常,根據異常對象是否為null,可以判斷是否出現(xiàn)異常。 不報錯也會執(zhí)行 |
whenCompletable | (T,Throwable) -> void | 類似handle 但是不返回結果 不報錯也會執(zhí)行 |
exceptionally | Throwable -> U | 出現(xiàn)異常時,返回一個結果 報錯時才會執(zhí)行。 |
completableOnTimeout | T, long, TimeUnit | 如果超時返回一個指定的結果。 超時后的鏈式操作都不執(zhí)行 |
orTimeout | long, TimeUnit | 超時返回一個異常 TimeOutException 超時后的鏈式操作都不執(zhí)行 |
thenRun | Runable | 執(zhí)行Runable,返回void,對于不需要任務的返回結果 |
示例
private static final ThreadPoolExecutor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(10, 10, 1, TimeUnit.MINUTES, new ArrayBlockingQueue<>(50));public static void main(String[] args) {CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName() + ":supplyAsync");return "supplyAsync";});completableFuture.thenApply((result) -> {System.out.println(Thread.currentThread().getName() + ":thenApply1 ");return result + "\nthenApply1";}).thenAccept((result) -> {System.out.println(Thread.currentThread().getName() + ":thenAccept ");}).thenCompose(result ->CompletableFuture.supplyAsync(() -> {try {System.out.println(Thread.currentThread().getName() + ":thenCompose ");TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {throw new RuntimeException(e);}return result + "\nthenCompose";}))// thenCompose 超時了,orTimeout 之前的的操作都將被忽略 之后的還會執(zhí)行.thenAccept((result) -> {System.out.println(Thread.currentThread().getName() + ":ignore ");})// .completeOnTimeout("completeOnTimeout", 1, TimeUnit.SECONDS)// 這里會拋出一個TimeOutException.orTimeout(1, TimeUnit.SECONDS)// throwable則可以獲取到 TimeOutException .handleAsync((result, throwable) -> {System.out.println(Thread.currentThread().getName() + ":handleAsync ");if (throwable == null) {return result;}throwable.printStackTrace();return result + "\nhandleAsync";}, THREAD_POOL_EXECUTOR)// 因為TimeOutException 被handleAsync處理了,所以這里也沒有異常了throwable為null.whenComplete((result, throwable) -> {System.out.println(Thread.currentThread().getName() + ":whenComplete ");if (throwable == null) {return;}throwable.printStackTrace();}).thenRun(() -> {System.out.println(Thread.currentThread().getName() + ":thenRun ");});try {Thread.sleep(5000); // 添加短暫的延遲 因為是異步任務這里不等待一下的話main線程就終止了} catch (InterruptedException e) {e.printStackTrace();}THREAD_POOL_EXECUTOR.shutdownNow();
}#### 執(zhí)行結果
ForkJoinPool.commonPool-worker-3:supplyAsync
ForkJoinPool.commonPool-worker-3:thenApply1
ForkJoinPool.commonPool-worker-3:thenAccept
ForkJoinPool.commonPool-worker-3:thenCompose
pool-1-thread-1:handleAsync
pool-1-thread-1:whenComplete
pool-1-thread-1:thenRun
java.util.concurrent.TimeoutException
注意回調時機即可。
Async回調
我們這里使用一個叫
handleAsync
的方法與普通的handle相比,他是執(zhí)行的線程發(fā)送了變化。
使用Async在大多數(shù)情況下都會是在一個新的線程下去幫我們執(zhí)行這個回調,而普通的則是在原有由原有執(zhí)行任務的線程去執(zhí)行這個回調。
這里的大多數(shù)情況是指我們在使用自定義線程池的時候。而我們的Fork-Join-Pool可能會為一些短暫的任務重用相同的線程,以減少線程的創(chuàng)建和銷毀開銷。
get、join
當我們的CompletableFuture提供了返回值的時候,我們可以通過get或者join方法來阻塞的得到這個結果
與之不同是get他可能會拋出異常,而join不會。通常我們使用join
組合CompletableFuture
可以根據某種條件去執(zhí)行兩個或者多個CompletableFuture
因為組合太多,這里就簡單描述下我自己比較常用的
方法 | 參數(shù) | 描述 |
---|---|---|
static allOf | CompletableFuture<?>… | 所以任務都執(zhí)行完成后完成,返回結果為void |
static anyOf | CompletableFuture<?>… | 任意任務都執(zhí)行完成后完成,返回結果為void |
示例
public static void main(String[] args) {// 1.兩個任務都執(zhí)行完成后才完成CompletableFuture.allOf(CompletableFuture.runAsync(()->{System.out.println("supplyAsync1");}),CompletableFuture.runAsync(()->{// 異步任務等待1秒try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("supplyAsync2");}));// 任意一個完成則完成CompletableFuture.anyOf(CompletableFuture.runAsync(()->{System.out.println("supplyAsync3");}),CompletableFuture.runAsync(()->{// 異步任務等待2秒try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("supplyAsync4");}));// 主線程只等待一秒 try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {throw new RuntimeException(e);}
}### 結果
supplyAsync1
supplyAsync3
supplyAsync2
allOf 因為需要兩個都完成所以等待一秒后完成輸出supplyAsync1、supplyAsync2
antOf 任意一個完成則算結束。因為第二個等待兩秒,主線程已經結束了,main已經退出了,所以只輸出supplyAsync3