1. 程式人生 > 其它 >01-CompletableFuture非同步執行緒 入門

01-CompletableFuture非同步執行緒 入門

前言

emmm, 有好長一段時間沒有釋出新的文章了,最後一篇釋出還是1月21日,到現在已經快3個月了,這段時間我去幹嘛了呢?

1: 學習資料結構與演算法, 但是還沒有學完,打算等學習完畢後再給大家分享

2: 學習Java 9 - 15的新特性, 應為關注Java的發展方向這一塊來說,基本是每個學習Java的人員所必備的, 為啥沒有16和17呢?應為我在網上沒有找到好的視訊,所以等以後找到了在學習而且新特特性應該不是很多,但是9-17加起來就很多了

3: 就是最近這段時間我離職了, 在交接和找新的工作,所很大一部分精力都用在了這個上面

但是今天給大家帶來了一個新的東西,這個東西用的人也比較少, 其實也不是很新,是Java8中的一個類而已,但是非常好用, 用過多執行緒的人應該都知道,執行緒的建立,回收,管理,池化,都很難弄, 但是學習了這個東西, 媽媽再也不用擔心我用不好多執行緒了

CompletableFuture是什麼

從名稱看來和Future有關,沒錯,他也是Future的實現,和FutureTask平級,也是用來實現非同步執行緒任務的,並且攜帶返回值, 具體的使用直接從需求出發,關注下面的需求和實現, 即可掌握

需求

小白來餐廳吃飯, 點了一盤番茄炒蛋+米飯,小白開始打王者,廚師開始炒菜,小白開吃

需求點: 廚師需要單獨的執行緒

實現

編寫程式碼

package com.dance;

import org.junit.jupiter.api.Test;

import java.util.StringJoiner;
import java.util.concurrent.CompletableFuture;

public class CompletableFutureTest { @Test public void testOne(){ print("小白進入餐廳"); print("小白點了 番茄炒蛋 + 一碗米飯"); CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> { print("廚師炒菜"); sleep(200); print("廚師打飯"); sleep(
100); return "番茄炒蛋 + 米飯 好了"; }); print("小白在打王者"); print(String.format("%s , 小白開吃", cf1.join())); } /** * 休眠方法 * @param millis 毫秒 */ public static void sleep(long millis){ try { Thread.sleep(millis); } catch (InterruptedException e) { e.printStackTrace(); } } /** * 列印方法 * @param text 文字 */ public static void print(String text){ String str = new StringJoiner("\t|\t") .add(String.valueOf(System.currentTimeMillis())) .add(String.valueOf(Thread.currentThread().getId())) .add(Thread.currentThread().getName()) .add(text) .toString(); System.out.println(str); } }

執行結果

1649430128924    |    1    |    main    |    小白進入餐廳
1649430128924    |    1    |    main    |    小白點了 番茄炒蛋 + 一碗米飯
1649430128926    |    1    |    main    |    小白在打王者
1649430128927    |    24    |    ForkJoinPool.commonPool-worker-19    |    廚師炒菜
1649430129134    |    24    |    ForkJoinPool.commonPool-worker-19    |    廚師打飯
1649430129244    |    1    |    main    |    番茄炒蛋 + 米飯 好了 , 小白開吃

廚師用單獨的執行緒去幹活了, 非同步執行緒,如此簡單

需求進化

在餐廳中一般廚師都只負責炒菜,像打飯這樣的事情都是交給服務員來的

需求點:廚師炒完菜後交給服務員,服務員新開執行緒去打飯

實現

編寫程式碼

@Test
public void testTwo(){
    print("小白進入餐廳");
    print("小白點了 番茄炒蛋 + 一碗米飯");
    CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
        print("廚師炒菜");
        sleep(200);
        return "番茄炒蛋";
    }).thenCompose(dis -> CompletableFuture.supplyAsync(() -> {
        print("服務員打飯");
        sleep(100);
        return dis + " + 米飯 好了";
    }));
    print("小白在打王者");
    print(String.format("%s , 小白開吃", cf1.join()));
}

執行結果

1649431094323    |    1    |    main    |    小白進入餐廳
1649431094324    |    1    |    main    |    小白點了 番茄炒蛋 + 一碗米飯
1649431094326    |    1    |    main    |    小白在打王者
1649431094326    |    24    |    ForkJoinPool.commonPool-worker-19    |    廚師炒菜
1649431094538    |    24    |    ForkJoinPool.commonPool-worker-19    |    服務員打飯
1649431094645    |    1    |    main    |    番茄炒蛋 + 米飯 好了 , 小白開吃

按道理來說這裡應該是兩個執行緒的,但是估計我這個執行的太快了,所以後面的任務也提交給了這個執行緒,我感覺這種程式碼呼叫流程就很清晰,看著像Promise

需求進化

小白進入餐廳的時候,開始點菜,要一盤番茄炒蛋+米飯, 但是這個時候米飯是沒有蒸好的,需要開始去蒸,所以廚師炒菜,服務員去蒸飯,這兩個事情應該是同時進行的,在廚師炒完菜,服務員蒸好飯,廚師將菜交給服務員,服務員打飯,交給小白,小白吃飯

需求點: 廚師炒菜和服務員蒸飯需要同時進行,並且是廚師炒完菜交給服務員

實現

編寫程式碼

@Test
public void testThree(){
    print("小白進入餐廳");
    print("小白點了 番茄炒蛋 + 一碗米飯");
    CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
        print("廚師炒菜");
        sleep(200);
        return "番茄炒蛋";
    }).thenCombine(CompletableFuture.supplyAsync(() -> {
        print("服務員開始蒸飯");
        sleep(300);
        return "米飯";
    }), (dis, rice) -> {
        print("服務員打飯");
        sleep(100);
        return String.format("%s + %s , 好了", dis, rice);
    });
    print("小白在打王者");
    print(String.format("%s , 小白開吃", cf1.join()));
}

執行結果

1649431885256    |    1    |    main    |    小白進入餐廳
1649431885256    |    1    |    main    |    小白點了 番茄炒蛋 + 一碗米飯
1649431885259    |    1    |    main    |    小白在打王者
1649431885259    |    24    |    ForkJoinPool.commonPool-worker-19    |    服務員開始蒸飯
1649431885259    |    25    |    ForkJoinPool.commonPool-worker-5    |    廚師炒菜
1649431885571    |    24    |    ForkJoinPool.commonPool-worker-19    |    服務員打飯
1649431885681    |    1    |    main    |    番茄炒蛋 + 米飯 , 好了 , 小白開吃

這裡出現了兩個執行緒,正好可以看到

總結

方法名

描述

supplyAsync

用來開啟一個非同步任務

thenCompose

用來連線兩個有依賴關係的任務,結果由最後一個返回

thenCombine

用來合併兩個任務,結果由函式(BiFunction)返回

第一個任務的需求點在於執行緒的開啟

第二個任務的需求點在於兩個執行緒的連線

第三個任務的需求點在於兩個執行緒的結果合併

怎麼樣到這裡是不是已經簡單的入門了呢

作者:彼岸舞

時間:2022\04\11

內容關於:CompeletableFuture

本文來源於網路,只做技術分享,一概不負任何責任