亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java多線程工具CompletableFuture怎么使用

發布時間:2022-08-25 17:00:43 來源:億速云 閱讀:229 作者:iii 欄目:開發技術

本文小編為大家詳細介紹“Java多線程工具CompletableFuture怎么使用”,內容詳細,步驟清晰,細節處理妥當,希望這篇“Java多線程工具CompletableFuture怎么使用”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。

    前言

    Future的問題

    寫多線程程序的時候,可以使用Future從一個異步線程中拿到結果,但是如果使用過程中會發現一些問題:

    • 如果想要對Future的結果做進一步的操作,需要阻塞當前線程

    • 多個Future不能被鏈式的執行,每個Future的結果都是獨立的,期望對一個Future的結果做另外一件異步的事情;

    • 沒有異常處理策略,如果Future執行失敗了,需要手動捕捉

    CompletableFuture應運而生

    為了解決Future問題,JDK在1.8的時候給我們提供了一個好用的工具類CompletableFuture;

    它實現了Future和CompletionStage接口,針對Future的不足之處給出了相應的處理方式。

    • 在異步線程執行結束后可以自動回調我們新的處理邏輯,無需阻塞

    • 可以對多個異步任務進行編排,組合或者排序

    • 異常處理

    CompletableFuture的核心思想是將每個異步任務都可以看做一個步驟(CompletionStage),然后其他的異步任務可以根據這個步驟做一些想做的事情。

    CompletionStage定義了許多步驟處理的方法,功能非常強大,這里就只列一下日常中常用到的一些方法供大家參考。

    使用方式

    基本使用-提交異步任務

    簡單的使用方式

    異步執行,無需結果:

    // 可以執行Executors異步執行,如果不指定,默認使用ForkJoinPool
    CompletableFuture.runAsync(() -> System.out.println("Hello CompletableFuture!"));

    異步執行,同時返回結果:

    // 同樣可以指定線程池
    CompletableFuture<String> stringCompletableFuture = CompletableFuture.supplyAsync(() -> "Hello CompletableFuture!");
    System.out.println(stringCompletableFuture.get());

    處理上個異步任務結果

    • thenRun: 不需要上一步的結果,直接直接新的操作

    • thenAccept:獲取上一步異步處理的內容,進行新的操作

    • thenApply: 獲取上一步的內容,然后產生新的內容

    所有加上Async后綴的,代表新的處理操作仍然是異步的。Async的操作都可以指定Executors進行處理

    Java多線程工具CompletableFuture怎么使用

    // Demo
           CompletableFuture
                    .supplyAsync(() -> "Hello CompletableFuture!")
                    // 針對上一步的結果做處理,產生新的結果
                    .thenApplyAsync(s -> s.toUpperCase())
                    // 針對上一步的結果做處理,不返回結果
                    .thenAcceptAsync(s -> System.out.println(s))
                    // 不需要上一步返回的結果,直接進行操作
                    .thenRunAsync(() -> System.out.println("end"));
            ;

    對兩個結果進行選用-acceptEither

    當我們有兩個回調在處理的時候,任何完成都可以使用,兩者結果沒有關系,那么使用acceptEither。

    兩個異步線程誰先執行完成,用誰的結果,其余類型的方法也是如此。

    Java多線程工具CompletableFuture怎么使用

    Java多線程工具CompletableFuture怎么使用

    // 返回abc
    CompletableFuture
                    .supplyAsync(() -> {
                        SleepUtils.sleep(100);
                        return "Hello CompletableFuture!";
                    })
                    .acceptEither(CompletableFuture.supplyAsync(() -> "abc"), new Consumer<String>() {
                        @Override
                        public void accept(String s) {
                            System.out.println(s);
                        }
                    });
    // 返回Hello CompletableFuture!       
    CompletableFuture
                    .supplyAsync(() -> "Hello CompletableFuture!")
                    .acceptEither(CompletableFuture.supplyAsync(() -> {
                        SleepUtils.sleep(100);
                        return "abc";
                    }), new Consumer<String>() {
                        @Override
                        public void accept(String s) {
                            System.out.println(s);
                        }
                    });

    對兩個結果進行合并-thenCombine, thenAcceptBoth

    thenCombine

    當我們有兩個CompletionStage時,需要對兩個的結果進行整合處理,然后計算得出一個新的結果。

    • thenCompose是對上一個CompletionStage的結果進行處理,返回結果,并且返回類型必須是CompletionStage。

    • thenCombine是得到第一個CompletionStage的結果,然后拿到當前的CompletionStage,兩者的結果進行處理。

            CompletableFuture<Integer> heightAsync = CompletableFuture.supplyAsync(() -> 172);
    
            CompletableFuture<Double> weightAsync = CompletableFuture.supplyAsync(() -> 65)
                    .thenCombine(heightAsync, new BiFunction<Integer, Integer, Double>() {
                        @Override
                        public Double apply(Integer wight, Integer height) {
                            return wight * 10000.0 / (height * height);
                        }
                    })
                    ;

    thenAcceptBoth

    需要兩個異步CompletableFuture的結果,兩者都完成的時候,才進入thenAcceptBoth回調。

    Java多線程工具CompletableFuture怎么使用

    Java多線程工具CompletableFuture怎么使用

    // thenAcceptBoth案例:
            CompletableFuture
                    .supplyAsync(() -> "Hello CompletableFuture!")
                    .thenAcceptBoth(CompletableFuture.supplyAsync(() -> "abc"), new BiConsumer<String, String>() {
                    		// 參數一為我們剛開始運行時的CompletableStage,新傳入的作為第二個參數
                        @Override
                        public void accept(String s, String s2) {
                            System.out.println("param1=" + s + ", param2=" + s2);
                        }
                    });
    // 結果:param1=Hello CompletableFuture!, param2=abc

    異常處理

    當我們使用CompleteFuture進行鏈式調用的時候,多個異步回調中,如果有一個執行出現問題,那么接下來的回調都會停止,所以需要一種異常處理策略。

    exceptionally

    exceptionally是當出現錯誤時,給我們機會進行恢復,自定義返回內容。

            CompletableFuture.supplyAsync(() -> {
                throw new RuntimeException("發生錯誤");
            }).exceptionally(throwable -> {
                log.error("調用錯誤 {}", throwable.getMessage(), throwable);
                return "異常處理內容";
            });

    handle

    exceptionally是只有發生異常時才會執行,而handle則是不管是否發生錯誤都會執行。

    CompletableFuture.supplyAsync(() -> {
        return "abc";
    })
    .handle((r,err) -> {
        log.error("調用錯誤 {}", err.getMessage(), err);
        // 對結果做額外的處理
        return r;
    })
    ;

    案例

    大量用戶發送短信|消息

    需求為對某個表中特定條件的用戶進行短信通知,但是短信用戶有成百上千萬,如果使用單線程讀取效率會很慢。這個時候可以考慮使用多線程的方式進行讀取;

    1、將讀取任務拆分為多個不同的子任務,指定讀取的偏移量和個數

      // 假設有500萬條記錄
            long recordCount = 500 * 10000;
            int subTaskRecordCount = 10000;
            // 對記錄進行分片
            List<Map> subTaskList = new LinkedList<>();
            for (int i = 0; i < recordCount / 500; i++) {
                // 如果子任務結構復雜,建議使用對象
                HashMap<String, Integer> subTask = new HashMap<>();
                subTask.put("index", i);
                subTask.put("offset", i * subTaskRecordCount);
                subTask.put("count", subTaskRecordCount);
                subTaskList.add(subTask);
            }

    2、使用多線程進行批量讀取

      // 進行subTask批量處理,拆分為不同的任務
            subTaskList.stream()
                    .map(subTask -> CompletableFuture.runAsync(()->{
                        // 讀取數據,然后處理
                        // dataTunel.read(subTask);
                    },excuturs))   // 使用應用的通用任務線程池
                    .map(c -> ((CompletableFuture<?>) c).join());

    3、進行業務邏輯處理,或者直接在讀取完進行業務邏輯處理也是可以;

    并發獲取商品不同信息

    在系統拆分比較細的時候,價格,優惠券,庫存,商品詳情等信息分散在不同的系統中,有時候需要同時獲取商品的所有信息, 有時候可能只需要獲取商品的部分信息。

    當然問題點在于要調用多個不同的系統,需要將RT降低下來,那么需要進行并發調用;

         List<Task> taskList = new ArrayList<>();
            List<Object> result = taskList.stream()
                    .map(task -> CompletableFuture.supplyAsync(()->{
    //                    handlerMap.get(task).query();
                        return "";
                    }, executorService))
                    .map(c -> c.join())
                    .collect(Collectors.toList());

    問題

    thenRun和thenRunAsync有什么區別

    • 如果不使用傳入的線程池,大家用默認的線程池ForkJoinPool

    • thenRun用的默認和上一個任務使用相同的線程池

    • thenRunAsync在執行新的任務的時候可以接受傳入一個新的線程池,使用新的線程池執行任務;

    handle和exceptional有什么區別

    exceptionally是只有發生異常時才會執行,而handle則是不管是否發生錯誤都會執行。

    讀到這里,這篇“Java多線程工具CompletableFuture怎么使用”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    德安县| 富民县| 苍梧县| 秦皇岛市| 东阳市| 淮南市| 满洲里市| 锡林浩特市| 聂荣县| 浮梁县| 游戏| 枣庄市| 米泉市| 六安市| 尼玛县| 乌拉特中旗| 神木县| 汉阴县| 乌什县| 武川县| 辽宁省| 铜山县| 宝应县| 贵溪市| 沂源县| 吉首市| 黑河市| 锡林浩特市| 思茅市| 措美县| 沙洋县| 嫩江县| 凤山市| 许昌县| 柳林县| 普格县| 永新县| 壤塘县| 彰武县| 大丰市| 江北区|