CompletableFuture接口說明
CompletableFuture是Future的子類,接口Future接口雖然實現了異步調用,但是存在一個問題,爲了判斷線程是否已完成計算,或者要獲取計算結果,我們需要不斷的輪詢,通過循環調用Future的isDone方法或者是直接調用get的方法阻塞線程。
在JDK8中,提供了CompletableFuture類來解決這類問題,它可以在線程完成計算後用when、then等方式調用我們定義後續處理方法,省去了輪詢的操作(筆者最近在讀RocketMQ源碼,發現在Broker上使用了CompletableFuture類,因此打算記錄一下基本功能和用法,希望後續有時間能詳細研讀一下實現源碼。)
CompletableFuture有以下幾種構造方式:
//沒有計算過程,直接返回計算結果
CompletableFuture<String>futureNoComplete=CompletableFuture.completedFuture("hello world");
//沒有返回值的異步計算
CompletableFuture<Void>futureNoReturnNoExecutor=CompletableFuture.runAsync(()->doSomething());
CompletableFuture<Void>futureNoReturnWithExecutor=CompletableFuture.runAsync(()->doSomething(), Executors.newSingleThreadExecutor());
//帶返回值的異步計算
CompletableFuture<String> futureWithReturnNoExector=CompletableFuture.supplyAsync(()->doSomethingReturnString());
CompletableFuture<String> futureWithReturnWithExecutor=CompletableFuture.supplyAsync(()->doSomethingReturnString(), Executors.newSingleThreadExecutor());
當completeFuture代表的任務完成了,可以使用一系列的函數接口來定義當前Future完成後的後續計算。
//執行完當前任務後,以當前任務的返回值作爲fn任務的輸入,並返回計算結果
public <U> CompletableFuture<U> thenApply(
Function<? super T,? extends U> fn) {
return uniApplyStage(null, fn);
}
//執行完當前任務後,將返回值作爲輸入,計算fn任務,並返回結果
public <U> CompletableFuture<U> thenApplyAsync(
Function<? super T,? extends U> fn) {
return uniApplyStage(asyncPool, fn);
}
//執行完當前任務後,以當前任務返回值作爲輸入,並返回計算結果,該計算過程使用executor中的不同線程來執行
public <U> CompletableFuture<U> thenApplyAsync(
Function<? super T,? extends U> fn, Executor executor) {
return uniApplyStage(screenExecutor(executor), fn);
}
//執行完當前任務後,將返回值作爲action任務的輸入參數進行計算
public CompletableFuture<Void> thenAccept(Consumer<? super T> action) {
return uniAcceptStage(null, action);
}
//執行完當前任務後,將返回值作爲action任務的輸入參數進行計算
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action) {
return uniAcceptStage(asyncPool, action);
}
//執行完當前任務後,將返回值作爲action任務的輸入參數進行計算
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action,
Executor executor) {
return uniAcceptStage(screenExecutor(executor), action);
}
//執行完當前任務後,執行action定義的任務
public CompletableFuture<Void> thenRun(Runnable action) {
return uniRunStage(null, action);
}
//執行完當前任務後,執行action任務
public CompletableFuture<Void> thenRunAsync(Runnable action) {
return uniRunStage(asyncPool, action);
}
//執行完當前任務後,執行action任務,action任務使用executor的線程執行
public CompletableFuture<Void> thenRunAsync(Runnable action,
Executor executor) {
return uniRunStage(screenExecutor(executor), action);
}
//執行完當前任務,和另一個CompletableFuture的任務other,將兩個任務的返回值作爲參數執行fn,返回該計算過程的CompletableFuture
public <U,V> CompletableFuture<V> thenCombine(
CompletionStage<? extends U> other,
BiFunction<? super T,? super U,? extends V> fn) {
return biApplyStage(null, other, fn);
}
//執行完當前任務,和另一個CompletableFuture的任務other,將兩個任務的返回值作爲參數執行fn,返回該計算過程的CompletableFuture
public <U,V> CompletableFuture<V> thenCombineAsync(
CompletionStage<? extends U> other,
BiFunction<? super T,? super U,? extends V> fn) {
return biApplyStage(asyncPool, other, fn);
}
//執行完當前任務,和另一個CompletableFuture的任務other,將兩個任務的返回值作爲參數執行fn,返回該計算過程的CompletableFuture,計算過程中會使用executor的線程計算
public <U,V> CompletableFuture<V> thenCombineAsync(
CompletionStage<? extends U> other,
BiFunction<? super T,? super U,? extends V> fn, Executor executor) {
return biApplyStage(screenExecutor(executor), other, fn);
}
//執行完當前任務,和另一個CompletableFuture的任務other,將兩個任務的返回值作爲參數執行fn
public <U> CompletableFuture<Void> thenAcceptBoth(
CompletionStage<? extends U> other,
BiConsumer<? super T, ? super U> action) {
return biAcceptStage(null, other, action);
}
//執行完當前任務,和另一個CompletableFuture的任務other,將兩個任務的返回值作爲參數執行fn
public <U> CompletableFuture<Void> thenAcceptBothAsync(
CompletionStage<? extends U> other,
BiConsumer<? super T, ? super U> action) {
return biAcceptStage(asyncPool, other, action);
}
//執行完當前任務,和另一個CompletableFuture的任務other,將兩個任務的返回值作爲參數執行fn,計算過程使用executor的線程執行
public <U> CompletableFuture<Void> thenAcceptBothAsync(
CompletionStage<? extends U> other,
BiConsumer<? super T, ? super U> action, Executor executor) {
return biAcceptStage(screenExecutor(executor), other, action);
}
//在當前任務和另一個CompletableFuture的任務執行完畢後,執行action
public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,
Runnable action) {
return biRunStage(null, other, action);
}
//在當前任務和另一個CompletableFuture的任務執行完畢後,執行action
public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
Runnable action) {
return biRunStage(asyncPool, other, action);
}
//在當前任務和另一個CompletableFuture的任務執行完畢後,執行action,計算過程會使用executor的線程執行
public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
Runnable action,
Executor executor) {
return biRunStage(screenExecutor(executor), other, action);
}
//計算當前任務與other的任務,計算快的返回結果作爲fn的輸入進行計算,並返回計算結果的CompleteFuture
public <U> CompletableFuture<U> applyToEither(
CompletionStage<? extends T> other, Function<? super T, U> fn) {
return orApplyStage(null, other, fn);
}
//計算當前任務與other的任務,計算快的返回結果作爲fn的數據進行計算,並返回計算結果的CompleteFuture
public <U> CompletableFuture<U> applyToEitherAsync(
CompletionStage<? extends T> other, Function<? super T, U> fn) {
return orApplyStage(asyncPool, other, fn);
}
//計算當前任務與other的任務,計算快的返回結果作爲fn的輸入進行計算,並返回計算結果的CompleteFuture,計算過程會使用executor的線程執行
public <U> CompletableFuture<U> applyToEitherAsync(
CompletionStage<? extends T> other, Function<? super T, U> fn,
Executor executor) {
return orApplyStage(screenExecutor(executor), other, fn);
}
//計算當前任務與other的任務,計算快的返回結果作爲action的輸入進行計算
public CompletableFuture<Void> acceptEither(
CompletionStage<? extends T> other, Consumer<? super T> action) {
return orAcceptStage(null, other, action);
}
//計算當前任務與other的任務,計算快的返回結果作爲action的輸入進行計算
public CompletableFuture<Void> acceptEitherAsync(
CompletionStage<? extends T> other, Consumer<? super T> action) {
return orAcceptStage(asyncPool, other, action);
}
//計算當前任務與other的任務,計算快的返回結果作爲action的輸入進行計算,計算過程使用executor的線程執行
public CompletableFuture<Void> acceptEitherAsync(
CompletionStage<? extends T> other, Consumer<? super T> action,
Executor executor) {
return orAcceptStage(screenExecutor(executor), other, action);
}
//當前任務和other的任務,只要有一個任務完成,就執行action
public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,
Runnable action) {
return orRunStage(null, other, action);
}
//當前任務和other的任務,只要有一個任務完成,就執行action
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
Runnable action) {
return orRunStage(asyncPool, other, action);
}
//當前任務和other的任務,只要有一個任務完成,就執行action,所有計算過程使用executor的線程
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
Runnable action,
Executor executor) {
return orRunStage(screenExecutor(executor), other, action);
}
//在當前的任務完成後,生成一個新的CompletableFuture
public <U> CompletableFuture<U> thenCompose(
Function<? super T, ? extends CompletionStage<U>> fn) {
return uniComposeStage(null, fn);
}
//在當前的任務完成後,生成一個新的CompletableFuture,與thenApply需要注意區別
public <U> CompletableFuture<U> thenComposeAsync(
Function<? super T, ? extends CompletionStage<U>> fn) {
return uniComposeStage(asyncPool, fn);
}
//在當前的任務完成後,生成一個新的CompletableFuture,計算過程使用executor的線程
public <U> CompletableFuture<U> thenComposeAsync(
Function<? super T, ? extends CompletionStage<U>> fn,
Executor executor) {
return uniComposeStage(screenExecutor(executor), fn);
}
//在當前任務完成後,執行action。該方法不會使用ForkJoinPool的線程,需要與thenapply區分
public CompletableFuture<T> whenComplete(
BiConsumer<? super T, ? super Throwable> action) {
return uniWhenCompleteStage(null, action);
}
//在當前任務完成後,執行action
public CompletableFuture<T> whenCompleteAsync(
BiConsumer<? super T, ? super Throwable> action) {
return uniWhenCompleteStage(asyncPool, action);
}
//在當前任務完成後,執行action,action是使用executor線程池執行
public CompletableFuture<T> whenCompleteAsync(
BiConsumer<? super T, ? super Throwable> action, Executor executor) {
return uniWhenCompleteStage(screenExecutor(executor), action);
}
CompleteFuture不帶Async和帶Async方法的區別:
- 帶Async的方法比較簡單,就是每個計算過程都會使用線程池中的線程來執行,如果沒有指定使用的線程池,那麼會使用默認的ForkJoinPool,如果指定了Executor,那麼直接使用指定的線程池即可。
- 不帶Async的方法執行較爲複雜,要分成兩種情況。
以thenAccept方法爲例:
第一種情況,在任務A還沒執行完的時候,主線程就通過thenAccept方法設置了任務A執行完後要執行任務B,代碼和對應的輸出結果如下:
CompletableFuture<String> completableFuture=CompletableFuture.supplyAsync(()->{
//分配了ForkJoinPool的線程執行
System.out.println("task A: "+Thread.currentThread());
try {
Thread.sleep(2000);
}catch (Exception e){
e.printStackTrace();
}
return "task A";
});
System.out.println(Thread.currentThread());
//Thread.sleep(5000);
completableFuture.thenAccept(str->{
System.out.println("task B: "+Thread.currentThread());
});
輸出結果:
Thread[main,5,main]
task A: Thread[ForkJoinPool.commonPool-worker-11,5,main]
task B: Thread[ForkJoinPool.commonPool-worker-11,5,main]
第二種情況,設置的任務A已經被子線程執行完畢,但是主線程還沒通過thenAccept方法去設置後續任務B的操作,那麼這個時候,只能由主線程執行任務B的操作,代碼和輸出如下:
CompletableFuture<String> completableFuture=CompletableFuture.supplyAsync(()->{
//分配了ForkJoinPool的線程執行
System.out.println("task A: "+Thread.currentThread());
try {
Thread.sleep(2000);
}catch (Exception e){
e.printStackTrace();
}
return "task A";
});
System.out.println(Thread.currentThread());
//等待子線程將任務A計算完成,再去設置任務B
Thread.sleep(5000);
completableFuture.thenAccept(str->{
System.out.println("task B: "+Thread.currentThread());
});
}
輸出結果:
Thread[main,5,main]
task A: Thread[ForkJoinPool.commonPool-worker-11,5,main]
task B: Thread[main,5,main]