最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java8?CompletableFuture?異步多線程的實(shí)現(xiàn)

 更新時(shí)間:2023年04月06日 11:16:10   作者:Q.E.D.  
本文主要介紹了Java8?CompletableFuture?異步多線程的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

1、一個(gè)示例回顧Future

一些業(yè)務(wù)場景我們需要使用多線程異步執(zhí)行任務(wù),加快任務(wù)執(zhí)行速度。

JDK5新增了Future接口,用于描述一個(gè)異步計(jì)算的結(jié)果。

雖然 Future 以及相關(guān)使用方法提供了異步執(zhí)行任務(wù)的能力,但是對于結(jié)果的獲取卻是很不方便,我們必須使用Future.get()的方式阻塞調(diào)用線程,或者使用輪詢方式判斷 Future.isDone 任務(wù)是否結(jié)束,再獲取結(jié)果。

這兩種處理方式都不是很優(yōu)雅,相關(guān)代碼如下:

    @Test
    public void testFuture() throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        Future<String> future = executorService.submit(() -> {
            Thread.sleep(2000);
            return "hello";
        });
        System.out.println(future.get());
        System.out.println("end");
    }

與此同時(shí),F(xiàn)uture無法解決多個(gè)異步任務(wù)需要相互依賴的場景,簡單點(diǎn)說就是,主線程需要等待子線程任務(wù)執(zhí)行完畢之后在進(jìn)行執(zhí)行,這個(gè)時(shí)候你可能想到了「CountDownLatch」,沒錯確實(shí)可以解決,代碼如下。

這里定義兩個(gè)Future,第一個(gè)通過用戶id獲取用戶信息,第二個(gè)通過商品id獲取商品信息。

    @Test
    public void testCountDownLatch() throws InterruptedException, ExecutionException {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        CountDownLatch downLatch = new CountDownLatch(2);
        long startTime = System.currentTimeMillis();
        Future<String> userFuture = executorService.submit(() -> {
            //模擬查詢商品耗時(shí)500毫秒
            Thread.sleep(500);
            downLatch.countDown();
            return "用戶A";
        });
 
        Future<String> goodsFuture = executorService.submit(() -> {
            //模擬查詢商品耗時(shí)500毫秒
            Thread.sleep(400);
            downLatch.countDown();
            return "商品A";
        });
 
        downLatch.await();
        //模擬主程序耗時(shí)時(shí)間
        Thread.sleep(600);
        System.out.println("獲取用戶信息:" + userFuture.get());
        System.out.println("獲取商品信息:" + goodsFuture.get());
        System.out.println("總共用時(shí)" + (System.currentTimeMillis() - startTime) + "ms");
 
    }

「運(yùn)行結(jié)果」

獲取用戶信息:用戶A
獲取商品信息:商品A
總共用時(shí)1110ms

從運(yùn)行結(jié)果可以看出結(jié)果都已經(jīng)獲取,而且如果我們不用異步操作,執(zhí)行時(shí)間應(yīng)該是:500+400+600 = 1500,用異步操作后實(shí)際只用1110。

但是Java8以后我不在認(rèn)為這是一種優(yōu)雅的解決方式,接下來來了解下CompletableFuture的使用。

2、通過CompletableFuture實(shí)現(xiàn)上面示例

    @Test
    public void testCompletableInfo() throws InterruptedException, ExecutionException {
        long startTime = System.currentTimeMillis();
 
        //調(diào)用用戶服務(wù)獲取用戶基本信息
        CompletableFuture<String> userFuture = CompletableFuture.supplyAsync(() ->
                //模擬查詢商品耗時(shí)500毫秒
        {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "用戶A";
        });
 
        //調(diào)用商品服務(wù)獲取商品基本信息
        CompletableFuture<String> goodsFuture = CompletableFuture.supplyAsync(() ->
                //模擬查詢商品耗時(shí)500毫秒
        {
            try {
                Thread.sleep(400);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "商品A";
        });
 
        System.out.println("獲取用戶信息:" + userFuture.get());
        System.out.println("獲取商品信息:" + goodsFuture.get());
 
        //模擬主程序耗時(shí)時(shí)間
        Thread.sleep(600);
        System.out.println("總共用時(shí)" + (System.currentTimeMillis() - startTime) + "ms");
    }

運(yùn)行結(jié)果

獲取用戶信息:用戶A
獲取商品信息:商品A
總共用時(shí)1112ms

通過CompletableFuture可以很輕松的實(shí)現(xiàn)CountDownLatch的功能,你以為這就結(jié)束了,遠(yuǎn)遠(yuǎn)不止,CompletableFuture比這要強(qiáng)多了。

比如可以實(shí)現(xiàn):任務(wù)1執(zhí)行完了再執(zhí)行任務(wù)2,甚至任務(wù)1執(zhí)行的結(jié)果,作為任務(wù)2的入?yún)?shù)等等強(qiáng)大功能,下面就來學(xué)學(xué)CompletableFuture的API。

3、CompletableFuture創(chuàng)建方式

3.1、常用的4種創(chuàng)建方式

CompletableFuture源碼中有四個(gè)靜態(tài)方法用來執(zhí)行異步任務(wù)

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier){..}
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor){..}
public static CompletableFuture<Void> runAsync(Runnable runnable){..}
public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor){..}

一般我們用上面的靜態(tài)方法來創(chuàng)建CompletableFuture,這里也解釋下他們的區(qū)別:

  • 「supplyAsync」執(zhí)行任務(wù),支持返回值。
  • 「runAsync」執(zhí)行任務(wù),沒有返回值。

3.1.1、「supplyAsync方法」

//使用默認(rèn)內(nèi)置線程池ForkJoinPool.commonPool(),根據(jù)supplier構(gòu)建執(zhí)行任務(wù)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
//自定義線程,根據(jù)supplier構(gòu)建執(zhí)行任務(wù)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)

3.1.2、「runAsync方法」

//使用默認(rèn)內(nèi)置線程池ForkJoinPool.commonPool(),根據(jù)runnable構(gòu)建執(zhí)行任務(wù)
public static CompletableFuture<Void> runAsync(Runnable runnable) 
//自定義線程,根據(jù)runnable構(gòu)建執(zhí)行任務(wù)
public static CompletableFuture<Void> runAsync(Runnable runnable,  Executor executor)

3.2、結(jié)果獲取的4種方式

對于結(jié)果的獲取CompltableFuture類提供了四種方式

//方式一
public T get()
//方式二
public T get(long timeout, TimeUnit unit)
//方式三
public T getNow(T valueIfAbsent)
//方式四
public T join()

說明:

  • 「get()和get(long timeout, TimeUnit unit)」 => 在Future中就已經(jīng)提供了,后者提供超時(shí)處理,如果在指定時(shí)間內(nèi)未獲取結(jié)果將拋出超時(shí)異常
  • 「getNow」 => 立即獲取結(jié)果不阻塞,結(jié)果計(jì)算已完成將返回結(jié)果或計(jì)算過程中的異常,如果未計(jì)算完成將返回設(shè)定的valueIfAbsent值
  • 「join」 => 方法里不會拋出異常

示例

    @Test
    public void testCompletableGet() throws InterruptedException, ExecutionException {
 
        CompletableFuture<String> cp1 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "商品A";
        });
 
        // getNow方法測試 
        System.out.println(cp1.getNow("商品B"));
 
        //join方法測試 
        CompletableFuture<Integer> cp2 = CompletableFuture.supplyAsync((() -> 1 / 0));
        System.out.println(cp2.join());
        System.out.println("-----------------------------------------------------");
        //get方法測試
        CompletableFuture<Integer> cp3 = CompletableFuture.supplyAsync((() -> 1 / 0));
        System.out.println(cp3.get());
    }

「運(yùn)行結(jié)果」:

  • 第一個(gè)執(zhí)行結(jié)果為 「商品B」,因?yàn)橐人?秒結(jié)果不能立即獲取
  • join方法獲取結(jié)果方法里不會拋異常,但是執(zhí)行結(jié)果會拋異常,拋出的異常為CompletionException
  • get方法獲取結(jié)果方法里將拋出異常,執(zhí)行結(jié)果拋出的異常為ExecutionException

4、異步回調(diào)方法

4.1、thenRun/thenRunAsync

通俗點(diǎn)講就是,「做完第一個(gè)任務(wù)后,再做第二個(gè)任務(wù),第二個(gè)任務(wù)也沒有返回值」。

示例

    @Test
    public void testCompletableThenRunAsync() throws InterruptedException, ExecutionException {
        long startTime = System.currentTimeMillis();
 
        CompletableFuture<Void> cp1 = CompletableFuture.runAsync(() -> {
            try {
                //執(zhí)行任務(wù)A
                Thread.sleep(600);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
 
        });
 
        CompletableFuture<Void> cp2 = cp1.thenRun(() -> {
            try {
                //執(zhí)行任務(wù)B
                Thread.sleep(400);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
 
        // get方法測試
        System.out.println(cp2.get());
 
        //模擬主程序耗時(shí)時(shí)間
        Thread.sleep(600);
        System.out.println("總共用時(shí)" + (System.currentTimeMillis() - startTime) + "ms");
    }
 
    //運(yùn)行結(jié)果
    /**
     *  null
     *  總共用時(shí)1610ms
     */

「thenRun 和thenRunAsync有什么區(qū)別呢?」

如果你執(zhí)行第一個(gè)任務(wù)的時(shí)候,傳入了一個(gè)自定義線程池:

  • 調(diào)用thenRun方法執(zhí)行第二個(gè)任務(wù)時(shí),則第二個(gè)任務(wù)和第一個(gè)任務(wù)是共用同一個(gè)線程池。
  • 調(diào)用thenRunAsync執(zhí)行第二個(gè)任務(wù)時(shí),則第一個(gè)任務(wù)使用的是你自己傳入的線程池,第二個(gè)任務(wù)使用的是ForkJoin線程池。

說明: 后面介紹的thenAccept和thenAcceptAsync,thenApply和thenApplyAsync等,它們之間的區(qū)別也是這個(gè)。

4.2、thenAccept/thenAcceptAsync

第一個(gè)任務(wù)執(zhí)行完成后,執(zhí)行第二個(gè)回調(diào)方法任務(wù),會將該任務(wù)的執(zhí)行結(jié)果,作為入?yún)?/strong>,傳遞到回調(diào)方法中,但是回調(diào)方法是沒有返回值的。

示例

    @Test
    public void testCompletableThenAccept() throws ExecutionException, InterruptedException {
        long startTime = System.currentTimeMillis();
        CompletableFuture<String> cp1 = CompletableFuture.supplyAsync(() -> {
            return "dev";
 
        });
        CompletableFuture<Void> cp2 = cp1.thenAccept((a) -> {
            System.out.println("上一個(gè)任務(wù)的返回結(jié)果為: " + a);
        });
 
        cp2.get();
    }

4.3、 thenApply/thenApplyAsync

表示第一個(gè)任務(wù)執(zhí)行完成后,執(zhí)行第二個(gè)回調(diào)方法任務(wù),會將該任務(wù)的執(zhí)行結(jié)果,作為入?yún)?,傳遞到回調(diào)方法中,并且回調(diào)方法是有返回值的。

示例

    @Test
    public void testCompletableThenApply() throws ExecutionException, InterruptedException {
        CompletableFuture<String> cp1 = CompletableFuture.supplyAsync(() -> {
            return "dev";
 
        }).thenApply((a) -> {
            if (Objects.equals(a, "dev")) {
                return "dev";
            }
            return "prod";
        });
 
        System.out.println("當(dāng)前環(huán)境為:" + cp1.get());
 
        //輸出: 當(dāng)前環(huán)境為:dev
    }

5、異?;卣{(diào)

當(dāng)CompletableFuture的任務(wù)不論是正常完成還是出現(xiàn)異常它都會調(diào)用「whenComplete」這回調(diào)函數(shù)。

  • 「正常完成」:whenComplete返回結(jié)果和上級任務(wù)一致,異常為null;
  • 「出現(xiàn)異?!?/strong>:whenComplete返回結(jié)果為null,異常為上級任務(wù)的異常;

即調(diào)用get()時(shí),正常完成時(shí)就獲取到結(jié)果,出現(xiàn)異常時(shí)就會拋出異常,需要你處理該異常。

下面來看看示例

5.1、只用whenComplete

    @Test
    public void testCompletableWhenComplete() throws ExecutionException, InterruptedException {
        CompletableFuture<Double> future = CompletableFuture.supplyAsync(() -> {
 
            if (Math.random() < 0.5) {
                throw new RuntimeException("出錯了");
            }
            System.out.println("正常結(jié)束");
            return 0.11;
 
        }).whenComplete((aDouble, throwable) -> {
            if (aDouble == null) {
                System.out.println("whenComplete aDouble is null");
            } else {
                System.out.println("whenComplete aDouble is " + aDouble);
            }
            if (throwable == null) {
                System.out.println("whenComplete throwable is null");
            } else {
                System.out.println("whenComplete throwable is " + throwable.getMessage());
            }
        });
        System.out.println("最終返回的結(jié)果 = " + future.get());
    }

正常完成,沒有異常時(shí):

正常結(jié)束
whenComplete aDouble is 0.11
whenComplete throwable is null
最終返回的結(jié)果 = 0.11

出現(xiàn)異常時(shí):get()會拋出異常

whenComplete aDouble is null
whenComplete throwable is java.lang.RuntimeException: 出錯了
 
java.util.concurrent.ExecutionException: java.lang.RuntimeException: 出錯了
 at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
 at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)

5.2、whenComplete + exceptionally示例

    @Test
    public void testWhenCompleteExceptionally() throws ExecutionException, InterruptedException {
        CompletableFuture<Double> future = CompletableFuture.supplyAsync(() -> {
            if (Math.random() < 0.5) {
                throw new RuntimeException("出錯了");
            }
            System.out.println("正常結(jié)束");
            return 0.11;
 
        }).whenComplete((aDouble, throwable) -> {
            if (aDouble == null) {
                System.out.println("whenComplete aDouble is null");
            } else {
                System.out.println("whenComplete aDouble is " + aDouble);
            }
            if (throwable == null) {
                System.out.println("whenComplete throwable is null");
            } else {
                System.out.println("whenComplete throwable is " + throwable.getMessage());
            }
        }).exceptionally((throwable) -> {
            System.out.println("exceptionally中異常:" + throwable.getMessage());
            return 0.0;
        });
 
        System.out.println("最終返回的結(jié)果 = " + future.get());
    }

當(dāng)出現(xiàn)異常時(shí),exceptionally中會捕獲該異常,給出默認(rèn)返回值0.0。

whenComplete aDouble is null
whenComplete throwable is java.lang.RuntimeException: 出錯了
exceptionally中異常:java.lang.RuntimeException: 出錯了
最終返回的結(jié)果 = 0.0

6、多任務(wù)組合回調(diào)

6.1、AND組合關(guān)系

thenCombine / thenAcceptBoth / runAfterBoth都表示:「當(dāng)任務(wù)一和任務(wù)二都完成再執(zhí)行任務(wù)三」。

區(qū)別在于:

  • 「runAfterBoth」 不會把執(zhí)行結(jié)果當(dāng)做方法入?yún)ⅲ覜]有返回值
  • 「thenAcceptBoth」: 會將兩個(gè)任務(wù)的執(zhí)行結(jié)果作為方法入?yún)?,傳遞到指定方法中,且無返回值
  • 「thenCombine」:會將兩個(gè)任務(wù)的執(zhí)行結(jié)果作為方法入?yún)?,傳遞到指定方法中,且有返回值

示例

    @Test
    public void testCompletableThenCombine() throws ExecutionException, InterruptedException {
        //創(chuàng)建線程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        //開啟異步任務(wù)1
        CompletableFuture<Integer> task = CompletableFuture.supplyAsync(() -> {
            System.out.println("異步任務(wù)1,當(dāng)前線程是:" + Thread.currentThread().getId());
            int result = 1 + 1;
            System.out.println("異步任務(wù)1結(jié)束");
            return result;
        }, executorService);
 
        //開啟異步任務(wù)2
        CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("異步任務(wù)2,當(dāng)前線程是:" + Thread.currentThread().getId());
            int result = 1 + 1;
            System.out.println("異步任務(wù)2結(jié)束");
            return result;
        }, executorService);
 
        //任務(wù)組合
        CompletableFuture<Integer> task3 = task.thenCombineAsync(task2, (f1, f2) -> {
            System.out.println("執(zhí)行任務(wù)3,當(dāng)前線程是:" + Thread.currentThread().getId());
            System.out.println("任務(wù)1返回值:" + f1);
            System.out.println("任務(wù)2返回值:" + f2);
            return f1 + f2;
        }, executorService);
 
        Integer res = task3.get();
        System.out.println("最終結(jié)果:" + res);
    }

「運(yùn)行結(jié)果」

異步任務(wù)1,當(dāng)前線程是:17
異步任務(wù)1結(jié)束
異步任務(wù)2,當(dāng)前線程是:18
異步任務(wù)2結(jié)束
執(zhí)行任務(wù)3,當(dāng)前線程是:19
任務(wù)1返回值:2
任務(wù)2返回值:2
最終結(jié)果:4

6.2、OR組合關(guān)系

applyToEither / acceptEither / runAfterEither 都表示:「兩個(gè)任務(wù),只要有一個(gè)任務(wù)完成,就執(zhí)行任務(wù)三」

區(qū)別在于:

  • 「runAfterEither」:不會把執(zhí)行結(jié)果當(dāng)做方法入?yún)?,且沒有返回值
  • 「acceptEither」: 會將已經(jīng)執(zhí)行完成的任務(wù),作為方法入?yún)?,傳遞到指定方法中,且無返回值
  • 「applyToEither」:會將已經(jīng)執(zhí)行完成的任務(wù),作為方法入?yún)ⅲ瑐鬟f到指定方法中,且有返回值

示例

    @Test
    public void testCompletableEitherAsync() {
        //創(chuàng)建線程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        //開啟異步任務(wù)1
        CompletableFuture<Integer> task = CompletableFuture.supplyAsync(() -> {
            System.out.println("異步任務(wù)1,當(dāng)前線程是:" + Thread.currentThread().getId());
 
            int result = 1 + 1;
            System.out.println("異步任務(wù)1結(jié)束");
            return result;
        }, executorService);
 
        //開啟異步任務(wù)2
        CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("異步任務(wù)2,當(dāng)前線程是:" + Thread.currentThread().getId());
            int result = 1 + 2;
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("異步任務(wù)2結(jié)束");
            return result;
        }, executorService);
 
        //任務(wù)組合
        task.acceptEitherAsync(task2, (res) -> {
            System.out.println("執(zhí)行任務(wù)3,當(dāng)前線程是:" + Thread.currentThread().getId());
            System.out.println("上一個(gè)任務(wù)的結(jié)果為:" + res);
        }, executorService);
    }

運(yùn)行結(jié)果

//通過結(jié)果可以看出,異步任務(wù)2都沒有執(zhí)行結(jié)束,任務(wù)3獲取的也是1的執(zhí)行結(jié)果
異步任務(wù)1,當(dāng)前線程是:17
異步任務(wù)1結(jié)束
異步任務(wù)2,當(dāng)前線程是:18
執(zhí)行任務(wù)3,當(dāng)前線程是:19
上一個(gè)任務(wù)的結(jié)果為:2

注意

如果把上面的核心線程數(shù)改為1也就是

 ExecutorService executorService = Executors.newFixedThreadPool(1);

運(yùn)行結(jié)果就是下面的了,會發(fā)現(xiàn)根本沒有執(zhí)行任務(wù)3,顯然是任務(wù)3直接被丟棄了。

異步任務(wù)1,當(dāng)前線程是:17
異步任務(wù)1結(jié)束
異步任務(wù)2,當(dāng)前線程是:17

6.3、多任務(wù)組合

  • 「allOf」:等待所有任務(wù)完成
  • 「anyOf」:只要有一個(gè)任務(wù)完成

示例

allOf:等待所有任務(wù)完成

    @Test
    public void testCompletableAallOf() throws ExecutionException, InterruptedException {
        //創(chuàng)建線程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        //開啟異步任務(wù)1
        CompletableFuture<Integer> task = CompletableFuture.supplyAsync(() -> {
            System.out.println("異步任務(wù)1,當(dāng)前線程是:" + Thread.currentThread().getId());
            int result = 1 + 1;
            System.out.println("異步任務(wù)1結(jié)束");
            return result;
        }, executorService);
 
        //開啟異步任務(wù)2
        CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("異步任務(wù)2,當(dāng)前線程是:" + Thread.currentThread().getId());
            int result = 1 + 2;
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("異步任務(wù)2結(jié)束");
            return result;
        }, executorService);
 
        //開啟異步任務(wù)3
        CompletableFuture<Integer> task3 = CompletableFuture.supplyAsync(() -> {
            System.out.println("異步任務(wù)3,當(dāng)前線程是:" + Thread.currentThread().getId());
            int result = 1 + 3;
            try {
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("異步任務(wù)3結(jié)束");
            return result;
        }, executorService);
 
        //任務(wù)組合
        CompletableFuture<Void> allOf = CompletableFuture.allOf(task, task2, task3);
 
        //等待所有任務(wù)完成
        allOf.get();
        //獲取任務(wù)的返回結(jié)果
        System.out.println("task結(jié)果為:" + task.get());
        System.out.println("task2結(jié)果為:" + task2.get());
        System.out.println("task3結(jié)果為:" + task3.get());
    }

anyOf: 只要有一個(gè)任務(wù)完成

    @Test
    public void testCompletableAnyOf() throws ExecutionException, InterruptedException {
        //創(chuàng)建線程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        //開啟異步任務(wù)1
        CompletableFuture<Integer> task = CompletableFuture.supplyAsync(() -> {
            int result = 1 + 1;
            return result;
        }, executorService);
 
        //開啟異步任務(wù)2
        CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(() -> {
            int result = 1 + 2;
            return result;
        }, executorService);
 
        //開啟異步任務(wù)3
        CompletableFuture<Integer> task3 = CompletableFuture.supplyAsync(() -> {
            int result = 1 + 3;
            return result;
        }, executorService);
 
        //任務(wù)組合
        CompletableFuture<Object> anyOf = CompletableFuture.anyOf(task, task2, task3);
        //只要有一個(gè)有任務(wù)完成
        Object o = anyOf.get();
        System.out.println("完成的任務(wù)的結(jié)果:" + o);
    }

7、CompletableFuture使用有哪些注意點(diǎn)

 CompletableFuture 使我們的異步編程更加便利的、代碼更加優(yōu)雅的同時(shí),我們也要關(guān)注下它,使用的一些注意點(diǎn)。

7.1、Future需要獲取返回值,才能獲取異常信息

    @Test
    public void testWhenCompleteExceptionally() {
        CompletableFuture<Double> future = CompletableFuture.supplyAsync(() -> {
            if (1 == 1) {
                throw new RuntimeException("出錯了");
            }
            return 0.11;
        });
 
        //如果不加 get()方法這一行,看不到異常信息
        //future.get();
    }

Future需要獲取返回值,才能獲取到異常信息。如果不加 get()/join()方法,看不到異常信息。

小伙伴們使用的時(shí)候,注意一下哈,考慮是否加try...catch...或者使用exceptionally方法。

7.2、CompletableFuture的get()方法是阻塞的

CompletableFuture的get()方法是阻塞的,如果使用它來獲取異步調(diào)用的返回值,需要添加超時(shí)時(shí)間。

//反例
 CompletableFuture.get();
//正例
CompletableFuture.get(5, TimeUnit.SECONDS);

7.3、不建議使用默認(rèn)線程池

CompletableFuture代碼中又使用了默認(rèn)的「ForkJoin線程池」,處理的線程個(gè)數(shù)是電腦「CPU核數(shù)-1」。在大量請求過來的時(shí)候,處理邏輯復(fù)雜的話,響應(yīng)會很慢。一般建議使用自定義線程池,優(yōu)化線程池配置參數(shù)。

7.4、自定義線程池時(shí),注意飽和策略

CompletableFuture的get()方法是阻塞的,我們一般建議使用future.get(5, TimeUnit.SECONDS)。并且一般建議使用自定義線程池。

但是如果線程池拒絕策略是DiscardPolicy或者DiscardOldestPolicy,當(dāng)線程池飽和時(shí),會直接丟棄任務(wù),不會拋棄異常。因此建議,CompletableFuture線程池策略最好使用AbortPolicy,然后耗時(shí)的異步線程,做好線程池隔離哈。

到此這篇關(guān)于Java8 CompletableFuture 異步多線程的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Java8 CompletableFuture 異步多線程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java對接微信支付之JSAPI支付(微信公眾號支付)

    java對接微信支付之JSAPI支付(微信公眾號支付)

    這篇文章主要給大家介紹了關(guān)于java對接微信支付之JSAPI支付(微信公眾號支付)的相關(guān)資料,微信JSAPI支付是近年來非常流行的一種支付方式,它使用了微信支付的SDK和demo來實(shí)現(xiàn)支付接口的對接,需要的朋友可以參考下
    2023-07-07
  • Java如何獲得泛型類中的泛型類型T.class

    Java如何獲得泛型類中的泛型類型T.class

    獲取泛型符號E的Class對象的方法,1.反射方案利用匿名子類實(shí)例化,但該方法有特殊限制,2.反射方案2直接指定泛型類型,但不靈活,3.構(gòu)造方法方案在初始化時(shí)傳入泛型類,但有寫錯風(fēng)險(xiǎn)
    2024-12-12
  • Mybatis-Plus樂觀鎖配置流程

    Mybatis-Plus樂觀鎖配置流程

    這篇文章主要介紹了Mybatis-Plus樂觀鎖配置使用流程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作有一定的參考學(xué)習(xí)價(jià)值,感興趣的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2024-01-01
  • SpringCloud鏈路追蹤組件Sleuth配置方法解析

    SpringCloud鏈路追蹤組件Sleuth配置方法解析

    這篇文章主要介紹了SpringCloud鏈路追蹤組件Sleuth配置方法解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • 使用Java實(shí)現(xiàn)對兩個(gè)秒級時(shí)間戳相加

    使用Java實(shí)現(xiàn)對兩個(gè)秒級時(shí)間戳相加

    在現(xiàn)代應(yīng)用程序開發(fā)中,時(shí)間戳的處理是一個(gè)常見需求,特別是當(dāng)我們需要對時(shí)間戳進(jìn)行運(yùn)算時(shí),比如時(shí)間戳的相加操作,本文我們將探討如何使用Java對兩個(gè)秒級時(shí)間戳進(jìn)行相加,并展示詳細(xì)的代碼示例和運(yùn)行結(jié)果,需要的朋友可以參考下
    2024-08-08
  • 關(guān)于Shiro過濾器配置方式(ShiroFilterFactoryBean)

    關(guān)于Shiro過濾器配置方式(ShiroFilterFactoryBean)

    這篇文章主要介紹了關(guān)于Shiro過濾器配置方式(ShiroFilterFactoryBean),具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Java編程反射機(jī)制用法入門與實(shí)例總結(jié)

    Java編程反射機(jī)制用法入門與實(shí)例總結(jié)

    這篇文章主要介紹了Java編程反射機(jī)制用法,簡單說明了反射機(jī)制的概念、原理并結(jié)合實(shí)例形式總結(jié)分析了java反射機(jī)制的簡單使用方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2017-12-12
  • Java 全排列的幾種實(shí)現(xiàn)方法

    Java 全排列的幾種實(shí)現(xiàn)方法

    本文詳細(xì)介紹了Java中全排列問題的幾種實(shí)現(xiàn)方法,包括回溯法、字典序排列法和迭代法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-11-11
  • Spring boot2X Consul如何使用Feign實(shí)現(xiàn)服務(wù)調(diào)用

    Spring boot2X Consul如何使用Feign實(shí)現(xiàn)服務(wù)調(diào)用

    這篇文章主要介紹了spring boot2X Consul如何使用Feign實(shí)現(xiàn)服務(wù)調(diào)用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12
  • Java高并發(fā)測試框架JCStress詳解

    Java高并發(fā)測試框架JCStress詳解

    這篇文章主要介紹了Java高并發(fā)測試框架JCStress,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04

最新評論

吴江市| 札达县| 辉县市| 蒙阴县| 常宁市| 邯郸市| 正安县| 名山县| 泸溪县| 洞口县| 图片| 东兰县| 鄂伦春自治旗| 保山市| 栾城县| 淄博市| 宿松县| 安阳市| 丰顺县| 阳新县| 托克逊县| 武定县| 宝鸡市| 含山县| 靖安县| 津南区| 米易县| 安宁市| 宁远县| 曲靖市| 山阳县| 清丰县| 蛟河市| 龙井市| 宣化县| 黔西县| 永新县| 左云县| 建水县| 岳阳市| 墨玉县|