欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入學習java8?中的CompletableFuture

 更新時間:2022年05月05日 08:56:47   作者:斜月?  
本文主要介紹了java8中的CompletableFuture,CompletableFuture實現了CompletionStage接口和Future接口,前者是對后者的一個擴展,增加了異步回調、流式處理、多個Future組合處理的能力,使Java在處理多任務的協同工作時更加順暢便利,下文需要的朋友可以參考一下

1 前言

在項目開發(fā)中,異步化處理是非常常見的解決問題的手段,異步化處理除了使用線程池之外,還可以使用 CompletableFuture 來實現,在多任務處理且之間存在邏輯關系的情況下,就能夠體現出其巨大的優(yōu)勢和靈活性。CompletableFuture 底層使用的是 ForkJoinPool 線程池來實現線程的執(zhí)行和調度。

2 簡單使用

在使用線程池時,通常的使用方法如下所示:

ExecutorService service = Executors.newFixedThreadPool(3);
Callable<String> task1 = () ->{return "task1";};
Runnable task2 = () ->{
      System.out.println("task2 ");
};
// 用于提交任務根據是否獲取返回值分為 Callable 和 Runnable,分別使用 submit 和 execute 方法
service.submit(task1);
service.execute(task2);

但是在 CompletableFuture 中,使用方法還是有所區(qū)別的,是線程池和任務的結合,能夠使用鏈式編程來處理任務之間的邏輯關系。

具體的使用如下所示:

// 使用默認線程池
CompletableFuture<String> async1 = CompletableFuture.supplyAsync(() -> {
       log.info("async1 ... ");
       return "async1";
});
// 使用自定義線程池
CompletableFuture<String> async1 = CompletableFuture.supplyAsync(() -> {
       log.info("async1 ... ");
       return "async1";
}, Executors.newSingleThreadExecutor());
// runAsync 的使用方式
CompletableFuture<Void> future = CompletableFuture.runAsync(()-> {
            System.out.println("runAsync");
});

異步任務的開啟一般有兩個方法,supplyAsync 和 runAsync,這兩個方法的別別在于:

  • 1 supplyAsync 不接受入參,但是會有返回結果。
  • 2 runAsync 也是不接受入參,但是沒有返回結果。

這里需要先說明一下,xxxAsync 的方法都是從使用線程池中獲取一個線程來處理任務,不帶 Async 結尾的方法則是使用上一任務的線程繼續(xù)處理。

3 異步處理

在正式開始之前,需要講解一下 java8 函數式編程的函數,相信大家看到這么多的函數都會頭暈的,但是其中也是有規(guī)律可循的,先說三個主要的:

  • 1 Function , 既然是函數,那么就會有一個入參和返回值,可以用于計算。
  • 2 Comsumer , 是一個消費者,接收一個入參但是沒有返回值,只用于消費。
  • 3 Supplier, 是一個提供者,不接受參數,但是有一個返回值,可以用于對象的創(chuàng)建。
  • 4 Predicate, 用來做判斷使用,接收一個入參,返回值是 布爾類型的,true 或者 false。

簡單的案例如下圖所示:

有這基本的 4 個,就可以進行延伸了,比如 IntFunction 則是接收一個 int 類型的參數,處理完成后即可返回,前面的 Int 只是規(guī)定了入參的類型而已,再有 BiConsumer , 則是接收兩個入參,Consumer 則是只能接收一個參數。依次類推就可以知道所有的函數式接口的功能,是不是很簡單?

3.1 thenApply

thenApply 和 thenApplyAsync 都是接收一個 Function 參數,即接收一個參數并返回結果。區(qū)別在于前者是使用前一個任務的線程繼續(xù)處理,后者是從線程池中在獲取一個線程處理任務。

如上圖所示,thenApply 的任務處理和 future 使用的是一個線程,但是 thenApplyAsync 就換了一個線程繼續(xù)數據的處理。

3.2 thenAccept 和 thenRun

從方法名可以看到 thenAccept 和 thenRun 都是使用前一個人任務的線程進行處理的。兩者都是在前一個任務完成后進行處理,區(qū)別點在于 thenAccept 接收的是一個 Consumer , 而 thenRun 接收的是一個 Runnable, 因此兩者都沒有返回值,但是前者可以接收并消費一個參數,但是 thenRun 不能接收參數。這兩個方法的測試如下圖所示:

既然這兩個方法已經搞清楚了,那么 thenAcceptAsync 和 thenRunAsync 是不是就順手學到了呢?異步編程的 API 真的是很簡單。

3.3 exceptionally 異常處理

exceptionally 屬于異常處理流程,如果發(fā)生異常則需要進行異常處理,需要將異常最為參數傳遞給 exceptionally, 而其需要的是一個 Function 參數,這里的異常處理也是同步進行的,也是采用上一個任務的線程進行處理。

// 拋出異常信息
CompletableFuture<String> exceptionally = future.exceptionally((ex) -> {
    log.info("error information " + ex.getLocalizedMessage());
    return ex.getMessage();
});

3.4 whenComplete 方法完成之后

這個方法是當某個任務執(zhí)行完成之后進行回調,會將任務的執(zhí)行結果或者執(zhí)行期間的異常信息傳遞過來進行處理,在正常的情況下,異常信息為 null,能夠得到任務的運算結果,異常情況下,異常信息不為空,返回結果為 null。這里的 whenComplete 接受的是一個 BiConsumer 函數,也就是兩個入參,沒有返回結果,一個是方法的返回結果,一個則是任務處理過程中的異常信息。

 // 返回結果
 CompletableFuture<String> whenComplete = future.whenComplete((res, ex) -> {
     if (StrUtil.isNotBlank(res)) {
         log.info("task execute result {}", res);
     }
     if (res != null) {
         log.info("task error info {}", ex.getMessage());
     }
 });

知道了 whenComplete 方法,那么 whenCompleteAsync 方法的使用就知道了,就是異步處理了。

3.5 handle

handle 的使用和 whenComplete 方法類似,都是獲取任務的結果,只不過 handle 有返回結果,接受的參數是一個 BiFunction ,那么具體的使用方法如下圖所示:

 // handle 處理返回結果
 CompletableFuture<String> handle = future.handle((res, ex) -> {
     if (StrUtil.isNotBlank(res)) {
         log.info("task execute result {}", res);
         return "handle result exception";
     }
     if (res != null) {
         log.info("task error info {}", ex.getMessage());
     }
     return "handle result";
 });

通過以上的分析,我們已經到得了以下規(guī)律:任何一個方法的實現都有三個類似的 API,一個是同步處理,一個是異步處理,一個是異步處理并指定線程池參數。目前已經介紹了 6 個 API,分別是 thenApplythenAccept,thenRunwhenCompletehandle 和 一個異常處理 exceptionally, 前五個舉一反三就知道了其他的兩個異步調用 API,掌握了其中的規(guī)律就不會覺得很多,無非就是同步異步,是否接收參數和有無返回值的區(qū)別。

4 處理組合

4.1 任務均完成后組合

thenCombinethenAcceptBoth、runAfterBoth 這三個方法都是在兩個 CompletableFuture 任務結束后在進行執(zhí)行,區(qū)別在于是否接受參數以及是否有返回值,如圖所示查看其接受的參數。

  • thenCombine 方法為兩個,第一個為 CompletionStage 對象即另一個異步任務,第二個為 BiFunction ,接收兩個任務的處理結果并返回處理結果。
  • thenAcceptBoth 方法為兩個,第一個為 CompletionStage 對象即另一個異步任務,第二個為 BiConsumer, 接收兩個任務的處理結果不過沒有返回值。
  • runAfterBoth 方法為兩個,第一個為 CompletionStage 對象即另一個異步任務,第二個為 Runnable ,不接收兩個任務的處理結果,也沒有返回值。

下圖是方法的使用案例:

既然知道了這些方法的用法,那么 thenCombineAsync、thenAcceptBothAsync、runAfterBothAsync 是不是就可以同理掌握了呢?

4.2 任一任務完成

前文提到的都是兩個任務均完成的情況,接下來的三個方法則是任何一個任務完成即可執(zhí)行下一個動作,applyToEither、acceptEitherrunAfterEither 這三個方法都是在兩個異步任務執(zhí)行結果之后的處理,任何一個任務執(zhí)行完畢之后就進行繼續(xù)處理。

這里的任一任務執(zhí)行完成和兩者任務都執(zhí)行完在執(zhí)行是類似的,區(qū)別在于這里接收的是一個參數:

  • 1 applyToEither 接收的參數是 CompletionStage 和 Function。
  • 2 acceptEither 接收的參數是 CompletionStage 和 Consumer。
  • 3 runAfterEither 接收的參數是 CompletionStage 和 Runnable。

這里已經學習到了 applyToEitheracceptEither、runAfterEither 三個方法,那么類似的 applyToEitherAsyncacceptEitherAsync、runAfterEitherAsync 也可以知道其具體用法。

4.3 任務處理結果

thenCompose 的用法和 thenCombine 等的用法基本都是一樣的,只不過在返回參數上有所區(qū)別,結果是返回一個 Future, 入參是一個 Function 。在了解了 thenCompose 之后,那么 thenComposeAsync 的使用方法就是類似了。

CompletableFuture<String> thenCompose = future.thenCompose((res) -> {
    log.info("result is {}", res);
    return CompletableFuture.supplyAsync(() -> {
        log.info("supplyAsync");
        return "result";
    });
});

4.4 所有或者任何

前面已經分享過了兩個任務和一個任務的處理之后的操作,在本節(jié)中將分享 allOf 和 anyOf,這是多個任務的聚合處理,入參都是多個 CompletableFuture, 區(qū)別在于是任何一個任務完成后就執(zhí)行后續(xù)任務,還是所有的任務都完成后再繼續(xù)任務處理。

其使用方法如下所示:

CompletableFuture<Void> allOf = CompletableFuture.allOf(future);
CompletableFuture<Object> andOf = CompletableFuture.anyOf(future);

5 總結

文中,我們首先介紹了函數式編程的接口使用方法,然后分享了 CompletableFuture 的 API 使用方法。核心就是函數式編程接口,接收的是 FunctionConsumer 還是 Runable , 其次就是否是 xxxAsync 異步處理。

到此這篇關于深入學習java8 中的CompletableFuture的文章就介紹到這了,更多相關java8 CompletableFuture 內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • java字符串抉擇

    java字符串抉擇

    下面給大家解析字符串連接方面的知識,包括string,stringbuffer和stringbuilder等方面的知識,對java字符串知識感興趣的朋友一起學習吧
    2016-12-12
  • Java設計模塊系列之書店管理系統單機版(一)

    Java設計模塊系列之書店管理系統單機版(一)

    這篇文章主要為大家詳細介紹了Java單機版的書店管理系統設計模塊和思想第一章,感興趣的小伙伴們可以參考一下
    2016-08-08
  • Java Collections.sort()排序代碼案例

    Java Collections.sort()排序代碼案例

    這篇文章主要介紹了Java Collections.sort()排序代碼案例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-02-02
  • spring boot 配置Filter過濾器的方法

    spring boot 配置Filter過濾器的方法

    本篇文章主要介紹了spring boot 配置Filter過濾器的方法,實例分析了spring boot 配置Filter過濾器的技巧,有興趣的可以了解一下。
    2017-03-03
  • SpringBoot使用攔截器Interceptor實現統一角色權限校驗

    SpringBoot使用攔截器Interceptor實現統一角色權限校驗

    角色權限校驗,是保證接口安全必備的能力:有權限才可以操作,所以,一般對于這種通用邏輯,推薦不與主業(yè)務邏輯耦合,那么怎么來解耦,那么本文小編就給大家詳細講解如何使用攔截器Interceptor實現統一角色權限校驗,需要的朋友可以參考下
    2023-07-07
  • 在springboot中注入FilterRegistrationBean不生效的原因

    在springboot中注入FilterRegistrationBean不生效的原因

    這篇文章主要介紹了在springboot中注入FilterRegistrationBean不生效的原因及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • java在運行時能修改工作目錄嗎

    java在運行時能修改工作目錄嗎

    這篇文章主要給大家介紹了關于java在運行時能修改工作目錄的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用java具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-08-08
  • Spring Boot jpa Service層代碼實例

    Spring Boot jpa Service層代碼實例

    這篇文章主要介紹了Spring Boot jpa Service層代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-10-10
  • Java雜談之類和對象 封裝 構造方法以及代碼塊詳解

    Java雜談之類和對象 封裝 構造方法以及代碼塊詳解

    在現實世界中,真實存在的東西,比如吉普車,卡丁車,貨車。我們在認識它的時候就會在腦海中將它抽象為一種類別叫做車。 好了,那再計算機世界中,它同樣的也會這樣做
    2021-09-09
  • 非常全面的Java異常處理(全文干貨,值得收藏)

    非常全面的Java異常處理(全文干貨,值得收藏)

    這篇文章主要給大家介紹了非常全面的Java異常處理的相關資料,全文干貨,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-11-11

最新評論