Java中CompletableFuture?的詳細(xì)介紹
1.概述
1.0 創(chuàng)建 CompletableFuture 的對象的工廠方法
static?CompletableFuture<Void> runAsync(Runnable?runnable) static?CompletableFuture<Void> runAsync(Runnable runnable, Executor executor) static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
runAsync 的參數(shù)是 Runnable, 返回值是 CompletableFuture, 意思是工廠方法創(chuàng)建的 CompletableFuture 對象封裝的任務(wù)沒有返回值。
例如:
CompletableFuture<Void> run = CompletableFuture.runAsync(()-> System.out.println("hello"));而 suppyAsync 參數(shù)類型是 Supplier,返回值是CompletableFuture<U> , 意思是任務(wù)不接受參數(shù),但是會返回結(jié)果。
CompletableFuture<String> supply = CompletableFuture.supplyAsync(() -> {
System.out.println("Hello");
return "hello world!"";
});
System.out.println(supply.get()); //hello world!"所以如果任務(wù)需要返回結(jié)果,那么應(yīng)該選擇 suppyAsync;否則可以選擇 runAsync。
1.1 non-async 和 async 區(qū)別
public CompletionStage<Void> thenRun(Runnable action); public CompletionStage<Void> thenRunAsync(Runnable action); public CompletionStage<Void> thenRunAsync(Runnable action,Executor executor);
CompletableFuture 中有眾多類似這樣的方法,那么 non-async 和 async 和版本的方法究竟有什么區(qū)別呢? 參考官方文檔的描述:
Actions supplied for dependent completions of non-async methods may be performed by the thread that completes the current CompletableFuture, or by any other caller of a completion method.
翻譯:傳遞給 non-async 方法作為參數(shù)的函數(shù)(action)可能會在完成當(dāng)前的 CompletableFuture 的線程中執(zhí)行,也可能會在方法的調(diào)用者線程中執(zhí)行。
All async methods without an explicit Executor argument are performed using the
ForkJoinPool.commonPool()(unless it does not support a parallelism level of at least two, in which case, a new Thread is created to run each task). To simplify monitoring, debugging, and tracking, all generated asynchronous tasks are instances of the marker interfaceCompletableFuture.AsynchronousCompletionTask.
翻譯:所有沒有Executor 參數(shù)的 async 方法都在 ForkJoinPool.commonPool()線程池中執(zhí)行(除非不支持最小并發(fā)度為2,這種情況下,每個任務(wù)會創(chuàng)建一個新線程去執(zhí)行)。為了簡化監(jiān)控、調(diào)試和追蹤,所有生成的異步任務(wù)都是接口 CompletableFuture.AsynchronousCompletionTask的實(shí)例。
從上面這兩段官方描述看。async 類方法比較容易理解,就是 CompletableFuture 實(shí)例的任務(wù)執(zhí)行完成后,會將 action 提交到缺省的異步線程池 ForkJoinPool.commonPool(),或者 async 類方法參數(shù)Executor executor 指定的線程池中執(zhí)行。
而對于 non-async 的描述則有點(diǎn)不明確。action 可能會在完成 CompletableFuture 實(shí)例任務(wù)的線程中執(zhí)行,也可能會在調(diào)用 thenRun(編排任務(wù)完成后執(zhí)行 action 的系列方法) 方法的線程中執(zhí)行。這個主要是看調(diào)用 thenRun 的時候,CompletableFuture 實(shí)例的任務(wù)是否已經(jīng)完成。如果沒有完成,那么action 會在完成任務(wù)的線程中執(zhí)行。如果任務(wù)已經(jīng)完成,則 action 會在調(diào)用thenAccept 等注冊方法的線程中執(zhí)行。
1.1.1 non-async 示例:注冊 action 的時候任務(wù)可能已經(jīng)結(jié)束
@Test
void testThenRunWithTaskCompleted() throws Exception{
CompletableFuture<Void> future = CompletableFuture.supplyAsync(new Supplier<Integer>() {
@Override
public Integer get() {
System.out.println("[" + Thread.currentThread().getName() + "] " + " in task" );
return 1;
}
}).thenRun(() -> {
System.out.println("[" + Thread.currentThread().getName() + "] " + " in action" );
});
future.get();
}運(yùn)行結(jié)果:
[ForkJoinPool.commonPool-worker-1] in task
[main] in action
分析: 任務(wù)通過 CompletableFuture.supplyAsync 提交后,會以異步的方式在 ForkJoinPool.commonPool() 線程池中運(yùn)行。這時候有兩個線程,一個是[ForkJoinPool.commonPool-worker-1] 執(zhí)行 Supplier.get 方法;一個是[main] 主線程提交完異步任務(wù)后,繼續(xù)調(diào)用 thenRun 編排任務(wù)完成后執(zhí)行 action。由于Supplier.get 非常簡單,幾乎立刻返回。所以很大概率在主線程調(diào)用 thenRun 編排任務(wù)完成后執(zhí)行 action的時候,異步任務(wù)已經(jīng)完成,所以 action 在主線程中執(zhí)行了。注:在筆者的電腦上幾乎100% 是這樣的調(diào)度方式。
1.1.2 non-async 示例:注冊 action 的時候任務(wù)未完成
@Test
void testThenRunWithTaskUncompleted() throws Exception{
CompletableFuture<Void> future = CompletableFuture.supplyAsync(new Supplier<Integer>() {
@Override
public Integer get() {
System.out.println("[" + Thread.currentThread().getName() + "] " + " in task" );
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new Random().nextInt(10);
}
}).thenRun(() -> {
System.out.println("[" + Thread.currentThread().getName() + "] " + " in action" );
});
future.get();
}運(yùn)行結(jié)果:
[ForkJoinPool.commonPool-worker-1] in task
[ForkJoinPool.commonPool-worker-1] in action
分析:在 Supplier.get 加入 sleep,延遲任務(wù)結(jié)束。主線程提交完異步任務(wù)后,繼續(xù)調(diào)用 thenRun 編排任務(wù)完成后執(zhí)行 action 的時候,任務(wù)沒有結(jié)束。所以這個action 在完成任務(wù)的線程中執(zhí)行。
1.2 Run 類方法
Run 類方法指 thenRun、runAfterBoth、runAfterEither 等。Run 類方法的動作參數(shù)都是Runable action。例如 thenRun(Runnable action)。這就意味著這個 action 不關(guān)心任務(wù)的結(jié)果,action 本身也沒有返回值。只是為了實(shí)現(xiàn)在完成任務(wù)后執(zhí)行一個動作的目的。
1.3 Accept 類方法
Accept 類方法指 thenAccept、runAcceptBoth、runAcceptEither 等。Accept 類方法的動作參數(shù)都是Consumer<? super T> action。例如 thenAccept(Consumer<? super T> action)。如方法名和參數(shù)所示,action 是接受并消費(fèi)任務(wù)結(jié)果的消費(fèi)者,action 沒有返回值。
1.4 Apply 類方法
Apply 類方法指 thenApply、applyToEither 等。Apply 類方法的動作參數(shù)都是Function<? super T,? extends U> fn。例如 thenApply(Function<? super T,? extends U> fn)。如方法名和參數(shù)所示,action 將任務(wù)結(jié)果應(yīng)用函數(shù)參數(shù) fn 做轉(zhuǎn)換,返回轉(zhuǎn)換后的結(jié)果,類似于 stream 中的 map。
2 單個任務(wù)執(zhí)行完成后執(zhí)行一個動作(action)
| 方法 | 說明 |
|---|---|
| public CompletableFuture<Void> thenRun(Runnable action) thenRunAsync(Runnable action) thenRunAsync(Runnable action, Executor executor) | 任務(wù)完成后執(zhí)行 action,action 中不關(guān)心任務(wù)的結(jié)果,action 也沒有返回值 |
| public CompletableFuture<Void> thenAccept(Consumer<? super T> action) thenAcceptAsync(Consumer<? super T> action) thenAcceptAsync(Consumer<? super T> action) | 任務(wù)完成后執(zhí)行 action。如方法名和參數(shù)所示,action 是接受并消費(fèi)任務(wù)結(jié)果的消費(fèi)者,action 沒有返回值 |
| public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn) thenApplyAsync(Function<? super T,? extends U> fn) thenApplyAsync(Function<? super T,? extends U> fn, Executor executor) | 任務(wù)完成后執(zhí)行 action。action 將任務(wù)結(jié)果應(yīng)用 action 的函數(shù)參數(shù)做轉(zhuǎn)換,返回轉(zhuǎn)換后的結(jié)果,類似于 stream 中的 map |
| public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action) whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action) whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, Executor executor) | 任務(wù)完成后或者異常時運(yùn)行action。action 是接受并消費(fèi)任務(wù)結(jié)果的消費(fèi)者,并且有返回值??梢哉J(rèn)為是支持異常處理的 thenAccept 版本。 |
| public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn) handleAsync(BiFunction<? super T, Throwable, ? extends U> fn) handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, Executor executor) | 任務(wù)完成后或者異常時運(yùn)行action。可以認(rèn)為是支持異常處理的 thenApply 版本。 |
| public CompletableFuture exceptionally(Function<Throwable, ? extends T> fn) | 如果任務(wù)或者 action 發(fā)生異常,則會觸發(fā)exceptionally的調(diào)用相當(dāng)于 try...catch |
2.0 示例 exceptionally
@Test
void testCompletableFutureExceptionally(){
CompletableFuture<Integer> first = CompletableFuture
.supplyAsync(() -> {
if (true) {
throw new RuntimeException("exception in task");
}
return "hello world";
})
.thenApply(data -> {
if (true) {
throw new RuntimeException("exception in action");
}
return 1;
})
.exceptionally(e -> {
System.out.println("[" + Thread.currentThread().getName() + "] " + " print exception stack trace" );
e.printStackTrace(); // 異常捕捉處理,前面兩個處理環(huán)節(jié)的日常都能捕獲
return 0;
});
}3 兩個任務(wù)執(zhí)行編排
下面表格列出的每個方法都有對應(yīng)兩個版本的 async 方法,一個有executor 參數(shù),一個沒有。為了表格盡量簡潔,表格中就不再列出async 方法了
| 方法 | 說明 |
|---|---|
| public <U> CompletableFuture<U> thenCompose(Function<? super T,? extends CompletionStage> fn) | 串行組合兩個 CompletableFuture 任務(wù),后一個任務(wù)依賴前一個任務(wù)的結(jié)果,后一個任務(wù)可以返回與第一個任務(wù)不同類型的返回值。執(zhí)行后一個任務(wù)的線程與前面討論 action 執(zhí)行的線程類似。 |
| public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other, Runnable action) | 這里有兩個并行任務(wù),一個是runAfterBoth 調(diào)用本身所屬的CompletableFuture 實(shí)例A,一個是參數(shù) other 引用的任務(wù)B。兩個并行任務(wù)都完成后執(zhí)行 action,action 中不關(guān)心任務(wù)的結(jié)果,action 也沒有返回值 |
| public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action) | 與runAfterBoth 類似,也有兩個并行任務(wù) A 和 B。兩個并行任務(wù)都完成后執(zhí)行 action。如方法名和參數(shù)所示,action 是接受并消費(fèi)兩個任務(wù)結(jié)果的消費(fèi)者,action 沒有返回值 |
| public <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn) | 與runAfterBoth 類似,也有兩個并行任務(wù) A 和 B。兩個并行任務(wù)都完成后執(zhí)行 action,action 依賴兩個任務(wù)的結(jié)果,并對結(jié)果做轉(zhuǎn)換,返回一個新值 |
| public CompletableFuture<Void> runAfterEither(CompletionStage<?> other, Runnable action) | 與runAfterBoth 類似,也有兩個并行任務(wù) A 和 B。兩個并行任務(wù)任意一個完成后執(zhí)行 action,action 中不關(guān)心任務(wù)的結(jié)果,action 也沒有返回值 |
| public CompletableFuture<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action) | 與runAfterBoth 類似,也有兩個并行任務(wù) A 和 B。兩個并行任務(wù)任意一個完成后執(zhí)行 action。如方法名和參數(shù)所示,action 是接受并消費(fèi)兩個任務(wù)結(jié)果的消費(fèi)者,action 沒有返回值 |
| public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn) | 與runAfterBoth 類似,也有兩個并行任務(wù) A 和 B。兩個并行任務(wù)任意一個完成后執(zhí)行 action。action 將任務(wù)結(jié)果應(yīng)用 action 的函數(shù)參數(shù)做轉(zhuǎn)換,返回轉(zhuǎn)換后的結(jié)果,類似于 stream 中的 map |
4 多個任務(wù)執(zhí)行編排
下面表格列出的每個方法都有對應(yīng)兩個版本的 async 方法,一個有executor 參數(shù),一個沒有。為了表格盡量簡潔,表格中就不再列出async 方法了
| 方法 | 說明 |
|---|---|
| public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) | 所有參數(shù)引用的任務(wù)都完成后,才觸發(fā)執(zhí)行當(dāng)前的 CompletableFuture 實(shí)例任務(wù)。 |
| public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) | 參數(shù)引用的任務(wù)中任何一個完成后,就會觸發(fā)執(zhí)行當(dāng)前的 CompletableFuture 實(shí)例任務(wù)。 |
5 CompletableFuture 其他方法
| 方法 | 說明 |
|---|---|
| public boolean cancel(boolean mayInterruptIfRunning) | 如果任務(wù)未完成,以 CancellationException 異常結(jié)束任務(wù)。 |
| public boolean isCancelled() | 判斷任務(wù)是否取消。 |
| public T join() | 阻塞等待 獲取返回值 |
| public T get() throws InterruptedException, ExecutionException public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException | 阻塞等待(有超時重載版本)獲取返回值。get 與 join區(qū)別,get 會拋出 checked 異常,調(diào)用代碼需要處理異常。join 沒有超時重載版本。 |
| public T getNow(T valueIfAbsent) | 獲取返回值,如果任務(wù)未完成則返回valueIfAbsent 參數(shù)指定value |
| public boolean isDone() | 任務(wù)是否執(zhí)行完成 |
到此這篇關(guān)于Java中CompletableFuture 的詳細(xì)介紹的文章就介紹到這了,更多相關(guān)CompletableFuture 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java實(shí)現(xiàn)的Base64加密算法示例
這篇文章主要介紹了Java實(shí)現(xiàn)的Base64加密算法,結(jié)合實(shí)例形式分析了Java實(shí)現(xiàn)的base64編碼轉(zhuǎn)換相關(guān)使用方法及操作注意事項(xiàng),需要的朋友可以參考下2018-04-04
Java如何實(shí)現(xiàn)讀取txt文件內(nèi)容并生成Word文檔
本文主要介紹了通過Java實(shí)現(xiàn)讀取txt文件中的內(nèi)容,并將內(nèi)容生成Word文檔。文章的代碼非常詳細(xì),具有一定的學(xué)習(xí)價值,感興趣的小伙伴可以了解一下2021-12-12
深入學(xué)習(xí)Hibernate持久化對象的三個狀態(tài)
Hibernate中的對象有3中狀態(tài),瞬時對象(TransientObjects)、持久化對象(PersistentObjects)和離線對象(DetachedObjects也叫做脫管對象),下面通過本文給大家分享Hibernate持久化對象的三個狀態(tài),一起看看吧2017-09-09
IDEA JarEditor編輯jar包方式(直接新增,修改,刪除jar包內(nèi)的class文件)
文章主要介紹了如何使用IDEA的JarEditor插件直接修改jar包內(nèi)的class文件,而不需要手動解壓、反編譯和重新打包,通過該插件,可以更方便地進(jìn)行jar包的修改和測試2025-01-01
Java如何利用Socket進(jìn)行數(shù)據(jù)讀寫
這篇文章主要介紹了Java如何利用Socket進(jìn)行數(shù)據(jù)讀寫,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10

