CompletableFuture详解~CompletionStage
CompletableFuture 分別實現兩個接口 Future與 CompletionStage。
Future 接口大家都比較熟悉,這里主要講講 CompletionStage。
CompletableFuture 大部分方法來自CompletionStage 接口,正是因為這個接口,CompletableFuture才有如此強大功能。
想要理解 CompletionStage 接口,我們需要先了解任務的時序關系的。我們可以將任務時序關系分為以下幾種:
-
串行執行關系
-
并行執行關系
-
AND 匯聚關系
-
OR 匯聚關系
1.串行執行關系
任務串行執行,下一個任務必須等待上一個任務完成才可以繼續執行。
?CompletionStage?有四組接口可以描述串行這種關系,分別為:
// 同步 CompletableFuture<U> thenApply(Function<? super T, ? extends u> fn) CompletableFuture<Void> thenAccept(Consumer<? super T> action) CompletableFuture<Void> thenRun(Runnable action) // 這個比較特殊,類似于Stream.flatmap CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn)// 異步 CompletionStage<U> thenApplyAsync(Function<? super T, ? extends u> fn) CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action) CompletionStage<Void> thenRunAsync(Runnable action) // 這個比較特殊,類似于Stream.flatmap CompletionStage<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn)thenApply?方法需要傳入核心參數為?Function<T,R>類型。這個類核心方法為:
R apply(T t)所以這個接口將會把上一個任務返回結果當做入參,執行結束將會返回結果。
thenAccept?方法需要傳入參數對象為?Consumer<T>類型,這個類核心方法為:
void accept(T t)返回值?void?可以看出,這個方法不支持返回結果,但是需要將上一個任務執行結果當做參數傳入。
thenRun?方法需要傳入參數對象為?Runnable?類型,這個類大家應該都比較熟悉,核心方法既不支持傳入參數,也不會返回執行結果。
thenCompose?方法作用與?thenApply?一樣,只不過?thenCompose?需要返回新的 ?CompletionStage。這么理解比較抽象,可以集合代碼一起理解。
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> "hello,樓下小哥");cf.thenApply(String::toLowerCase); // 需要重新創建一個CompletionStage cf.thenCompose(s -> CompletableFuture.supplyAsync(s::toLowerCase));方法中帶有?Async?,代表可以異步執行,這個系列還有重載方法,可以傳入自定義的線程池,上圖未展示,讀者只可以自行查看 API。
最后我們通過代碼展示?thenApply?使用方式:
CompletableFuture<String> cf= CompletableFuture.supplyAsync(() -> "hello,樓下小哥")// 1.thenApply(s -> s + "@程序通事") // 2.thenApply(String::toUpperCase); // 3System.out.println(cf.join()); // 輸出結果 HELLO,樓下小哥@程序通事這段代碼比較簡單,首先我們開啟一個異步任務,接著串行執行后續兩個任務。任務 2 需要等待任務1 執行完成,任務 3 需要等待任務 2。
| 上面方法,大家需要記住了 ?Function<T,R>,Consumer<T>,Runnable?三者區別,根據場景選擇使用。 |
2.AND 匯聚關系
?
如上所示,只有任務 A 與任務 B 都完成之后,任務 C 才會開始執行。
CompletionStage?有以下接口描述這種關系。
// 同步 CompletableFuture<V> thenCombine(CompletionStage<U> other, BiFunction<T,U,V> fn) CompletableFuture<Void> thenAcceptBoth(CompletionStage<U> other, BiConsumer<T,U> action) CompletableFuture<Void> runAfterBoth(CompletionStage<U> other, Runnable action)// 異步 CompletableFuture<V> thenCombineAsync(CompletionStage<U> other, BiFunction<T,U,V> fn) CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<U> other, BiConsumer<T,U> action) CompletableFuture<Void> runAfterBothAsync(CompletionStage<U> other, Runnable action)// 多組任務 static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)thenCombine?方法核心參數?BiFunction?,作用與?Function一樣,只不過?BiFunction?可以接受兩個參數,而?Function?只能接受一個參數。
thenAcceptBoth?方法核心參數BiConsumer?作用也與?Consumer一樣,不過其需要接受兩個參數。
runAfterBoth??方法核心參數最簡單,上面已經介紹過,不再介紹。
這三組方法只能完成兩個任務 AND 匯聚關系,如果需要完成多個任務匯聚關系,需要使用?CompletableFuture#allOf,不過這里需要注意,這個方法是不支持返回任務結果。
AND 匯聚關系相關示例代碼,開頭已經使用過了,這里再粘貼一下,方便大家理解:
// 任務1.訂購航班 CompletableFuture<String> orderAirplane = CompletableFuture.supplyAsync(() -> {System.out.println("查詢航班");sleep(3, TimeUnit.SECONDS);System.out.println("訂購航班");return "航班信息"; });// 任務2.訂購酒店 CompletableFuture<String> orderHotel = CompletableFuture.supplyAsync(() -> {System.out.println("查詢酒店");sleep(5, TimeUnit.SECONDS);System.out.println("訂購酒店");return "酒店信息"; });// 任務3.任務1和任務2都完成,才能去訂購租車服務 CompletableFuture<String> hireCar = orderHotel.thenCombine(orderAirplane, (airplane, hotel) -> {System.out.println("根據航班和酒店訂購租車服務");sleep(5, TimeUnit.SECONDS);return "租車信息"; });// 等待任務3執行結果 System.out.println(hireCar.join());// 執行結果 查詢航班 查詢酒店 訂購航班 訂購酒店 根據航班和酒店訂購租車服務 租車信息3.OR 匯聚關系
有 AND 匯聚關系,當然也存在 OR 匯聚關系。OR 匯聚關系代表只要多個任務中任一任務完成,就可以接著接著執行下一任務。
CompletionStage?有以下接口描述這種關系:
// 同步 CompletableFuture<V> applyToEither(CompletionStage<U> other, Function<T,U> fn) CompletableFuture<Void> acceptEither(CompletionStage<U> other, Consumer<T> action) CompletableFuture<Void> runAfterEither(CompletionStage<U> other, Runnable action)// 異步 CompletableFuture<V> applyToEitherAsync(CompletionStage<U> other, Function<T,U> fn) CompletableFuture<Void> acceptEitherAsync(CompletionStage<U> other, Consumer<T> action) CompletableFuture<Void> runAfterEitherAsync(CompletionStage<U> other, Runnable action)// 多組任務 static CompletableFuture<Void> anyOf(CompletableFuture<?>... cfs)前面三組接口方法傳參與 AND 匯聚關系一致,這里也不再詳細解釋了。
當然 OR 匯聚關系可以使用?CompletableFuture#anyOf?執行多個任務。
下面示例代碼展示如何使用?applyToEither?完成 OR 關系。
CompletableFuture<String> cf= CompletableFuture.supplyAsync(() -> {sleep(5, TimeUnit.SECONDS);return "hello,樓下小哥"; });// 1CompletableFuture<String> cf2 = cf.supplyAsync(() -> {sleep(3, TimeUnit.SECONDS);return "hello,程序通事"; }); // 執行 OR 關系 CompletableFuture<String> cf3 = cf2.applyToEither(cf, s -> s);// 輸出結果,由于 cf2 只休眠 3 秒,優先執行完畢 System.out.println(cf2.join()); // 結果:hello,程序通事?
4.異常處理
CompletableFuture??方法執行過程若產生異常,當調用?get,join獲取任務結果才會拋出異常。
CompletableFuture<Integer> cf = CompletableFuture.supplyAsync(() -> (66/0)).thenApply(r -> r*10);System.out.println(cf.join());// java.util.concurrent.CompletionException:java.lang.ArithmeticException: / by zero上面代碼我們顯示使用?try..catch?處理上面的異常。不過這種方式不太優雅,CompletionStage?提供幾個方法,可以優雅處理異常。
// 同步 CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn) CompletableFuture<T> whenComplete(BiConsumer<T, ? super Throwable> action) CompletableFuture<T> handle(BiFunction<T, Throwable, ? extends U> fn)// 異步 CompletableFuture<T> whenCompleteAsync(BiConsumer<T, ? super Throwable> action) CompletableFuture<T> handleAsync(BiFunction<T, Throwable, ? extends U> fn)exceptionally?使用方式類似于?try..catch?中?catch代碼塊中異常處理。
whenComplete?與?handle?方法就類似于?try..catch..finanlly?中?finally?代碼塊。無論是否發生異常,都將會執行的。這兩個方法區別在于 ?handle??支持返回結果。
下面示例代碼展示?handle?用法:
CompletableFuture<Integer>f0 = CompletableFuture.supplyAsync(() -> (7 / 0)).thenApply(r -> r * 10).handle((integer, throwable) -> {// 如果異常存在,打印異常,并且返回默認值if (throwable != null) {throwable.printStackTrace();return 0;} else {// 如果return integer;}});System.out.println(f0.join()); /***java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero* .....* * 0*/總結
以上是生活随笔為你收集整理的CompletableFuture详解~CompletionStage的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Awesome Mac:收集的非常全面好
- 下一篇: MediaWiki初探:安装及使用入门