CompletableFuture使用詳解

在多線程中,使用線程池時使用Future獲得異步執行結果時,要麼調用阻塞方法get(),要麼輪詢看isDone()是否爲true,這兩種方法都不是很好,因爲主線程也會被迫等待。
從Java 8開始引入了CompletableFuture,它針對Future做了改進,可以傳入回調對象,當異步任務完成或者發生異常時,自動調用回調對象的回調方法。

一.CompletableFuture簡介

Future可明確地完成(設定其值和狀態),並且可以被用作CompletionStage,支持相關的功能和動作的,其完成後觸發。
當兩個或多個線程嘗試對 complete, completeExceptionally或 cancel CompletableFuture進行操作時,只有其中一個成功。

除了直接操作狀態和結果的這些方法和相關方法之外,CompletableFuture還CompletionStage使用以下策略實現接口:

  • 爲非異步方法的相關完成提供的動作 可以由完成當前CompletableFuture的線程執行,也可以由完成方法的任何其他調用者執行。
  • 所有沒有顯式Executor參數的異步方法都使用來執行ForkJoinPool.commonPool() (除非它不支持並行度至少爲2,在這種情況下,將創建一個新的Thread來運行每個任務)。爲了簡化監視,調試和跟蹤,所有生成的異步任務都是標記接口的實例CompletableFuture.AsynchronousCompletionTask。
  • 所有CompletionStage方法都是獨立於其他公共方法實現的,因此一個方法的行爲不受子類中其他方法的覆蓋影響。

CompletableFuture還Future採用以下策略實施

  • 由於(與FutureTask此類不同)此類無法直接控制導致其完成的計算,因此取消被視爲異常完成的另一種形式。方法cancel具有與相同的效果 completeExceptionally(new CancellationException())。方法 isCompletedExceptionally()可用於確定CompletableFuture是否以任何特殊方式完成。
  • 如果使用CompletionException異常完成,則方法get()和get(long, TimeUnit)拋出具有 ExecutionException與相應CompletionException中所保存的原因相同的原因。爲了簡化大多數情況下的用法,此類還定義了方法,join()並且 getNow(T)在這些情況下直接拋出CompletionException。

二.常用Api介紹與實戰

2.1 runAsync

  • runAsync(Runnable runnable)
    返回一個新的CompletableFuture,它在運行給定操作後由運行在 ForkJoinPool.commonPool()中的任務 異步完成。
  • runAsync(Runnable runnable, Executor executor)
    返回一個新的CompletableFuture,它在運行給定操作之後由在給定執行程序中運行的任務異步完成。

代碼示例

  @SneakyThrows
  public static void main(String[] args) {
        CompletableFuture<Void> cf2 = CompletableFuture.runAsync(() -> {
            set(6.0, 10.0);
        });
        Thread.sleep(2000);
    }

    public static Double set(Double x,Double y){
        System.out.println("X="+x + "---- Y="+y);
        return Double.sum(x,y);
    }

2.2 supplyAsync

  • supplyAsync(Supplier supplier)
    返回一個新的CompletableFuture,它通過在 ForkJoinPool.commonPool()中運行的任務與通過調用給定的供應商獲得的值 異步完成。
  • supplyAsync(Supplier supplier, Executor executor)
    返回一個新的CompletableFuture,由給定執行器中運行的任務異步完成,並通過調用給定的供應商獲得的值
    代碼示例
    @SneakyThrows
    public static void main(String[] args) {
        CompletableFuture<Double> cf2 = CompletableFuture.supplyAsync(() -> {
            return set(6.0, 10.0);
        });
        Thread.sleep(2000);
    }

    public static Double set(Double x,Double y){
        System.out.println("X="+x + "---- Y="+y);
        return Double.sum(x,y);
    }

2.3 thenAccept和exceptionally

  • thenAccept(Consumer<? super T> action)
    返回一個新的CompletionStage,當此階段正常完成時,將以該階段的結果作爲提供的操作的參數執行。
  • exceptionally(Function<Throwable,? extends T> fn)
    返回一個新的CompletableFuture,當CompletableFuture完成時完成,結果是異常觸發此CompletableFuture的完成特殊功能的給定功能; 否則,如果此CompletableFuture正常完成,則返回的CompletableFuture也會以相同的值正常完成。
    代碼示例
 @SneakyThrows
    public static void main(String[] args) {
        CompletableFuture<Double> cf2 = CompletableFuture.supplyAsync(() -> {
            return set(6.0, 10.0);
        });
        //成功後執行
        cf2.thenAccept((sum)->{
            System.out.println("最終的值爲:"+sum);
        });
        //失敗執行
        cf2.exceptionally((e)->{
            e.printStackTrace();
            return null;
        });
        Thread.sleep(2000);
    }

    public static Double set(Double x,Double y){
        System.out.println("X="+x + "---- Y="+y);
        return Double.sum(x,y);
    }

2.4 串行與並行

2.4.1 串行

   @SneakyThrows
    public static void main(String[] args) {
        CompletableFuture<Double> cf2 = CompletableFuture.supplyAsync(() -> {
            return set(6.0, 10.0);
        });
        //成功後執行 執行下一個
        CompletableFuture<Double> cf3 = cf2.thenApplyAsync((setUp) -> {
           return setUp(10.0,9.98);
        });
        cf2.thenAccept(sum-> System.out.println("sum:"+sum));
        cf3.thenAccept(sum-> System.out.println("setUp:"+sum));
        //失敗執行
        cf2.exceptionally((e)->{
            e.printStackTrace();
            return null;
        });
        Thread.sleep(2000);
    }

    @SneakyThrows
    public static Double set(Double x, Double y){
        System.out.println("X="+x + "---- Y="+y);
        Thread.sleep(500);
        return Double.sum(x,y);
    }

    @SneakyThrows
    public static Double setUp(Double x, Double y){
        System.out.println("X="+x + "---- Y="+y);
        Thread.sleep(500);
        return Double.sum(x,y);
    }

執行結果
在這裏插入圖片描述

2.4.2 並行

  • allOf(CompletableFuture<?>… cfs)
    返回一個新的CompletableFuture,當所有給定的CompletableFutures完成時,完成。
  • anyOf(CompletableFuture<?>… cfs)
    返回一個新的CompletableFuture,當任何一個給定的CompletableFutures完成時,完成相同的結果。
    @SneakyThrows
    public static void main(String[] args) {
        //創建兩個異步的 CompletableFuture
        CompletableFuture<Double> cf2 = CompletableFuture.supplyAsync(() -> {
            return set(6.0, 10.0);
        });
        CompletableFuture<Double> cf3 = CompletableFuture.supplyAsync(() -> {
           return setUp(10.0,9.98);
        });
        //將 cf2 cf3 進行合併
        CompletableFuture<Object> objcf = CompletableFuture.anyOf(cf2, cf3);
        // 分別執行 ,獲取 相應的返回值
        CompletableFuture<Object> obj1 = objcf.thenApplyAsync(set -> {
            return set;
        });
        CompletableFuture<Object> obj2 = objcf.thenApplyAsync(setUp -> {
            return setUp;
        });
        //在次合併
        CompletableFuture<Object> objectCompletableFuture = CompletableFuture.anyOf(obj1, obj2);
        //統一sum
        objectCompletableFuture.thenAccept(result->{
            System.out.println("sum:"+result);
        });
        Thread.sleep(2000);
    }

    @SneakyThrows
    public static Double set(Double x, Double y){
        System.out.println("X="+x + "---- Y="+y);
        Thread.sleep(500);
        return Double.sum(x,y);
    }

    @SneakyThrows
    public static Double setUp(Double x, Double y){
        System.out.println("X="+x + "---- Y="+y);
        Thread.sleep(500);
        return Double.sum(x,y);
    }

執行結果
在這裏插入圖片描述
實際應用示例:
https://github.com/Dylan-haiji/javayh-platform/blob/master/javayh-starter/javayh-common-starter/src/main/java/com/javayh/common/exception/GlobalExceptionHandler.java

本文的分享暫時就到這裏,希望對您有所幫助
關注 Java有貨領取更多資料

聯繫小編。微信:372787553,帶您進羣互相學習
左側小編微信,右側獲取免費資料
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章