Java多執行緒開發CompletableFuture的應用

2023-03-19 21:12:21

​做Java程式設計,難免會遇到多執行緒的開發,但是JDK8這個CompletableFuture類很多開發者目前還沒聽說過,但是這個類實在是太好用了,瞭解它的一些用法後相信你會對它愛不釋手(呸渣男,咋對誰都愛不釋手呢),好了我先簡單舉個列子,告訴你用它有多好。Single Dog拿一個Appointment來舉個列子,如下:

/**
     * 女神化完妝之後,還需要一小會選衣服,不過分吧。
     * 也就是說我們現在有2個非同步任務,第一個是化妝,第二個是選衣服。
     * 選衣服要在化妝完成之後進行,這兩個任務是序列
     */
    public static void main(String[] args) {
        // 執行緒池我前面的文章聊過,怎麼設定可以去了解一下
       ThreadPoolExecutor threadPool= new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
        //任務1
        CompletableFuture<String> makeUpFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "-女神,開始化妝了");
            try {
                // 化妝的時間
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "化妝完畢了。";
        }, threadPool);
       //任務2,makeUp是呼叫方,意思是makeUpFuture執行完後再執行
        CompletableFuture<String> dressFuture = makeUpFuture.thenApply((result) -> {
            System.out.println(Thread.currentThread().getName() + "-女神" + result + "我開始選衣服啦,好了叫你!");
            try {
                // 換衣服的時間
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return result + "衣服也選好了,走出去玩吧!";
        });
        dressFuture.thenAccept((result) -> {
            System.out.println(Thread.currentThread().getName() + "-" + result);
        });
    }

上面的2個任務也可以理解為我們開發中要實現的不同功能,看明白前面的列子了吧?用它來寫多執行緒運用的多絲滑。那我們就先講一下它的核心的靜態的方法,推薦用它的靜態方法不要直接new物件。

1:無返回值的靜態方法:

​public static CompletableFuture<Void> runAsync(Runnable runnable)。

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

上面一個2個方法,如果沒有指定Executor就使用預設的ForkJoinPool.commonPool()執行緒池,如果指定執行緒池就使用指定的。

 

2:有返回值的方法

​public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)

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

如果開始的程式碼你還看不懂那介紹了上面的幾個方法就先小試牛刀一下:

ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
​
        CompletableFuture.runAsync(() -> {
            System.out.println(Thread.currentThread().getName());
            int i = 10 / 2;
            System.out.println("執行的結果是:" + i);
        }, threadPool);
​
        CompletableFuture future = CompletableFuture.supplyAsync(() -> {
                    try {
                        Thread.sleep(2);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return "Hello World";
                }, threadPool);
        System.out.println(future.get());

好了講過它的使用方法了那我們就聊一下它的幾個使用的場景,開發中這寫場景應該會使用到。

​1:執行任務 A,執行任務B,待任務B執行完成後,用B的返回值區執行任務C。

ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
        CompletableFuture<String> futureA = CompletableFuture.supplyAsync(() ->
        {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("執行任務A");
            return "任務A";
        }, executor);
        CompletableFuture<String> futureB = CompletableFuture.supplyAsync(() -> {
            System.out.println("執行任務B");
            return "任務B";
        }, executor);
        CompletableFuture<String> futurec = futureB.thenApply((b) -> {
            System.out.println("執行任務C");
            System.out.println("引數:" + b);
            return "a";
        });
        System.out.println(futurec.get());

​執行結果,注意我上面沒說B一定要在A執行以後執行。

 

 

 ​場景2:多個任務串聯執行,下一個任務的執行依賴上一個任務的結果,每個任務都有輸入和輸出。

ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
        CompletableFuture futureA = CompletableFuture.supplyAsync(() -> "Hello", executor);
        CompletableFuture futureB = futureA.thenApply((a) -> a + " World");
        CompletableFuture futureC = futureB.thenApply((b) -> b);
        System.out.println(futureC.join());

​輸出結果,開發中的經典場景輸出:

 

 ​場景3:thenCombineAsync 聯合 futureA和futureB的返回結果,然後在返回相關的資料

 ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
        CompletableFuture<Integer> futureA = CompletableFuture.supplyAsync(() -> 10, executor);
        CompletableFuture<Integer> futureB = CompletableFuture.supplyAsync(() -> 20, executor);
        CompletableFuture futureC = futureA.thenCombineAsync(futureB, (r1, r2) -> {
            System.out.println("r1的值為:" + r1 + ":r2的值為:" + r2);
            return r1 + r2;
        });
        System.out.println(futureC.get());

​結果輸出:

 

 好了聊完幾個場景那就寫一個在開發中的經典運用。

ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
        System.out.println("start...");
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("查詢商品資訊1");
            return "future1";
        }, executor);
​
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("查詢商品資訊2");
            return "future2";
        }, executor);
​
        CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
            System.out.println("查詢商品資訊3");
            return "future3";
        }, executor);
​
        final CompletableFuture<Void> voidCompletableFuture = CompletableFuture.allOf(future1, future2, future3);
        voidCompletableFuture.get();
        System.out.println("end...future1的結果:" + future1.get() + ",future2的結果:" + future2.get() + ",future3的結果:" + future3.get());

​輸出結果

​這個經典的應用相信你可以在你的開發中進行套用,然後靈活的運用。當然這個類還有很多的方法,我這裡只寫了部分介紹了部分場景作為一個引子,如果想了解它的更多的應用可以看它的API的檔案。

聊了這麼多你應該對我剛開始寫的那段程式碼瞭如指掌。這麼好用的類,歡迎你分享給其他的人,讓更多人知曉一下。它運用到開發中,應該能為你的開發提供很多的便利。一束光,二束光,三束光。分享的多了文章慢慢就回也得更好看,更精彩了。