【JDK8】Java8 優雅的異步調用API CompletableFuture


1.CompletableFuture是什么?

  CompletableFuture是JDK8的新特性之一,是異步調用相關的API,用於簡化異步調用,提高異步調用的效率

2.CompletableFuture有什么用?

  CompletableFuture 是對 Future對象的增強(JDK1.5),解決了異步調用中的很多問題:

  例如:多個異步任務之間的結果依賴問題,獲取future結果時阻塞主線程的問題,以及提供了很多豐富的API用於函數式編程

3.CompletableFuture怎么用?

  核心的API

  1.supplyAsync(參數1,指定異步任務(有返回值),參數2(可選)指定特定的線城池,如果不指定則使用默認線城池ForkJoin)

    CompletableFuture<U> supplyAsync(Supplier<U> supplier)

    CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor)

  2.runAsync(參數1,指定異步任務(無返回值),參數2(可選)指定特定的線城池,如果不指定則使用默認線城池ForkJoin)

    CompletableFuture<Void> runAsync(Runnable runnable)

    CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)

  備注:
    使用公共的 ForkJoinPool 線程池執行,這個線程池默認線程數是 CPU 的核數。可以設置 JVM option:-Djava.util.concurrent.ForkJoinPool.common.parallelism 來設置 ForkJoinPool 線程池的線程數,使用共享線程池將會有個弊端,一旦有任務被阻塞,將會造成其他任務沒機會執行。

    所以強烈建議根據任務類型不同,主動創建線程池,進行資源隔離,避免互相干擾。

4.Demo實例

  1.適合場景,將多個串行的操作轉換為並行的操作,提高接口響應速度

  2.函數式編程簡化多線程異步操作的代碼

@Override
    public CustomerTargetTrendVO customerTargetTrend(TargetTrendDTO targetTrendDTO) throws Exception {
        //構造查詢條件
        TrendQueryDTO queryDTO = buildTrendQueryDTO(targetTrendDTO);
        if (ObjectUtils.isEmpty(queryDTO)) {
            return new CustomerTargetTrendVO();
        }
        log.info("TrendQueryDTO : [{}]", queryDTO);

        //下單客戶數趨勢
        CompletableFuture<List<CustomerTargetTrendVO.OrdedCustomerItem>> ordedCustomerFuture =
                CompletableFuture.supplyAsync(() -> dmRptWgysEnterpriseSumMapper.countOrdCustomerTrend(queryDTO))
                        .thenApply(x -> JSON.parseArray(JSON.toJSONString(x), CustomerTargetTrendVO.OrdedCustomerItem.class));

        //下單實際采購量趨勢
        CompletableFuture<List<CustomerTargetTrendVO.PurchaseAreaItem>> purchaseAreaFuture =
                CompletableFuture.supplyAsync(() -> dmRptWgysCustomerOrderDetailMapper.countPurchaseAreaTrend(queryDTO))
                        .thenApply(x -> JSON.parseArray(JSON.toJSONString(x), CustomerTargetTrendVO.PurchaseAreaItem.class));

        //等待子線程任務完成
        CompletableFuture.allOf(ordedCustomerFuture, purchaseAreaFuture).join();

        //數據組裝
        List<CustomerTargetTrendVO.OrdedCustomerItem> dbOrdedCustomerList = ordedCustomerFuture.get();
        List<CustomerTargetTrendVO.PurchaseAreaItem> purchaseAreaList = purchaseAreaFuture.get();

        return CustomerTargetTrendVO.builder().ordedCustomerList(dbOrdedCustomerList).purchaseAreaList(purchaseAreaList).build();
    }

 

5.異常處理:
    CompletableFuture  方法執行過程若產生異常,當調用 getjoin獲取任務結果才會拋出異常。

    使用 whenComplete / handle 可以更加優雅的處理異常,whenComplete 與 handle 方法就類似於 try..catch..finanlly 中 finally 代碼塊。無論是否發生異常,都將會執行的。這兩個方法區別在於  handle  支持返回結果。

    

     //handle 同步處理
    public <U> CompletionStage<U> handle
        (BiFunction<? super T, Throwable, ? extends U> fn);
    
    //handle 異步處理
    public <U> CompletionStage<U> handleAsync
        (BiFunction<? super T, Throwable, ? extends U> fn);

    //handle 異步處理
    public <U> CompletionStage<U> handleAsync
        (BiFunction<? super T, Throwable, ? extends U> fn,
         Executor executor);

 

    //whenComplete 同步處理異常
    public CompletableFuture<T> whenComplete(
        BiConsumer<? super T, ? super Throwable> action) {
        return uniWhenCompleteStage(null, action);
    }
    //whenComplete 異步處理異常
    public CompletableFuture<T> whenCompleteAsync(
        BiConsumer<? super T, ? super Throwable> action) {
        return uniWhenCompleteStage(asyncPool, action);
    }

   

CompletableFuture<Integer>
        f0 = CompletableFuture.supplyAsync(() -> (7 / 0))
        .thenApply(r -> r * 10)
        .handle((integer, throwable) -> {
            // 如果異常存在,打印異常,並且返回默認值
            if (throwable != null) {
                throwable.printStackTrace();
                return 0;
            } else {
                // 如果
                return integer;
            }
        });

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM