精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

異步編程利器:CompletableFuture詳解

開發(fā) 項(xiàng)目管理
最近剛好使用CompeletableFuture優(yōu)化了項(xiàng)目中的代碼,所以跟大家一起學(xué)習(xí)CompletableFuture。

[[403915]]

前言

最近剛好使用CompeletableFuture優(yōu)化了項(xiàng)目中的代碼,所以跟大家一起學(xué)習(xí)CompletableFuture。

一個(gè)例子回顧 Future

因?yàn)镃ompletableFuture實(shí)現(xiàn)了Future接口,我們先來回顧Future吧。

Future是Java5新加的一個(gè)接口,它提供了一種異步并行計(jì)算的功能。如果主線程需要執(zhí)行一個(gè)很耗時(shí)的計(jì)算任務(wù),我們就可以通過future把這個(gè)任務(wù)放到異步線程中執(zhí)行。主線程繼續(xù)處理其他任務(wù),處理完成后,再通過Future獲取計(jì)算結(jié)果。

來看個(gè)簡(jiǎn)單例子吧,假設(shè)我們有兩個(gè)任務(wù)服務(wù),一個(gè)查詢用戶基本信息,一個(gè)是查詢用戶勛章信息。如下,

  1. public class UserInfoService { 
  2.  
  3.     public UserInfo getUserInfo(Long userId) throws InterruptedException { 
  4.         Thread.sleep(300);//模擬調(diào)用耗時(shí) 
  5.         return new UserInfo("666""撿田螺的小男孩", 27); //一般是查數(shù)據(jù)庫(kù),或者遠(yuǎn)程調(diào)用返回的 
  6.     } 
  7.  
  8. public class MedalService { 
  9.  
  10.     public MedalInfo getMedalInfo(long userId) throws InterruptedException { 
  11.         Thread.sleep(500); //模擬調(diào)用耗時(shí) 
  12.         return new MedalInfo("666""守護(hù)勛章"); 
  13.     } 

接下來,我們來演示下,在主線程中是如何使用Future來進(jìn)行異步調(diào)用的。

  1. public class FutureTest { 
  2.  
  3.     public static void main(String[] args) throws ExecutionException, InterruptedException { 
  4.  
  5.         ExecutorService executorService = Executors.newFixedThreadPool(10); 
  6.  
  7.         UserInfoService userInfoService = new UserInfoService(); 
  8.         MedalService medalService = new MedalService(); 
  9.         long userId =666L; 
  10.         long startTime = System.currentTimeMillis(); 
  11.  
  12.         //調(diào)用用戶服務(wù)獲取用戶基本信息 
  13.         FutureTask<UserInfo> userInfoFutureTask = new FutureTask<>(new Callable<UserInfo>() { 
  14.             @Override 
  15.             public UserInfo call() throws Exception { 
  16.                 return userInfoService.getUserInfo(userId); 
  17.             } 
  18.         }); 
  19.         executorService.submit(userInfoFutureTask); 
  20.  
  21.         Thread.sleep(300); //模擬主線程其它操作耗時(shí) 
  22.  
  23.         FutureTask<MedalInfo> medalInfoFutureTask = new FutureTask<>(new Callable<MedalInfo>() { 
  24.             @Override 
  25.             public MedalInfo call() throws Exception { 
  26.                 return medalService.getMedalInfo(userId); 
  27.             } 
  28.         }); 
  29.         executorService.submit(medalInfoFutureTask); 
  30.  
  31.         UserInfo userInfo = userInfoFutureTask.get();//獲取個(gè)人信息結(jié)果 
  32.         MedalInfo medalInfo = medalInfoFutureTask.get();//獲取勛章信息結(jié)果 
  33.  
  34.         System.out.println("總共用時(shí)" + (System.currentTimeMillis() - startTime) + "ms"); 
  35.     } 
  36.      

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

  1. 總共用時(shí)806ms 

如果我們不使用Future進(jìn)行并行異步調(diào)用,而是在主線程串行進(jìn)行的話,耗時(shí)大約為300+500+300 = 1100 ms。可以發(fā)現(xiàn),future+線程池異步配合,提高了程序的執(zhí)行效率。

但是Future對(duì)于結(jié)果的獲取,不是很友好,只能通過阻塞或者輪詢的方式得到任務(wù)的結(jié)果。

  • Future.get() 就是阻塞調(diào)用,在線程獲取結(jié)果之前get方法會(huì)一直阻塞。
  • Future提供了一個(gè)isDone方法,可以在程序中輪詢這個(gè)方法查詢執(zhí)行結(jié)果。

阻塞的方式和異步編程的設(shè)計(jì)理念相違背,而輪詢的方式會(huì)耗費(fèi)無謂的CPU資源。因此,JDK8設(shè)計(jì)出CompletableFuture。CompletableFuture提供了一種觀察者模式類似的機(jī)制,可以讓任務(wù)執(zhí)行完成后通知監(jiān)聽的一方。

一個(gè)例子走進(jìn)CompletableFuture

我們還是基于以上Future的例子,改用CompletableFuture 來實(shí)現(xiàn)

  1. public class FutureTest { 
  2.  
  3.     public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException { 
  4.  
  5.         UserInfoService userInfoService = new UserInfoService(); 
  6.         MedalService medalService = new MedalService(); 
  7.         long userId =666L; 
  8.         long startTime = System.currentTimeMillis(); 
  9.  
  10.         //調(diào)用用戶服務(wù)獲取用戶基本信息 
  11.         CompletableFuture<UserInfo> completableUserInfoFuture = CompletableFuture.supplyAsync(() -> userInfoService.getUserInfo(userId)); 
  12.  
  13.         Thread.sleep(300); //模擬主線程其它操作耗時(shí) 
  14.  
  15.         CompletableFuture<MedalInfo> completableMedalInfoFuture = CompletableFuture.supplyAsync(() -> medalService.getMedalInfo(userId));  
  16.  
  17.         UserInfo userInfo = completableUserInfoFuture.get(2,TimeUnit.SECONDS);//獲取個(gè)人信息結(jié)果 
  18.         MedalInfo medalInfo = completableMedalInfoFuture.get();//獲取勛章信息結(jié)果 
  19.         System.out.println("總共用時(shí)" + (System.currentTimeMillis() - startTime) + "ms"); 
  20.  
  21.     } 

可以發(fā)現(xiàn),使用CompletableFuture,代碼簡(jiǎn)潔了很多。CompletableFuture的supplyAsync方法,提供了異步執(zhí)行的功能,線程池也不用單獨(dú)創(chuàng)建了。實(shí)際上,它CompletableFuture使用了默認(rèn)線程池是ForkJoinPool.commonPool。

CompletableFuture提供了幾十種方法,輔助我們的異步任務(wù)場(chǎng)景。這些方法包括創(chuàng)建異步任務(wù)、任務(wù)異步回調(diào)、多個(gè)任務(wù)組合處理等方面。我們一起來學(xué)習(xí)吧

CompletableFuture使用場(chǎng)景

創(chuàng)建異步任務(wù)

CompletableFuture創(chuàng)建異步任務(wù),一般有supplyAsync和runAsync兩個(gè)方法

創(chuàng)建異步任務(wù)

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

supplyAsync方法

//使用默認(rèn)內(nèi)置線程池ForkJoinPool.commonPool(),根據(jù)supplier構(gòu)建執(zhí)行任務(wù)

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

runAsync方法

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

實(shí)例代碼如下:

  1. public class FutureTest { 
  2.  
  3.     public static void main(String[] args) { 
  4.         //可以自定義線程池 
  5.         ExecutorService executor = Executors.newCachedThreadPool(); 
  6.         //runAsync的使用 
  7.         CompletableFuture<Void> runFuture = CompletableFuture.runAsync(() -> System.out.println("run,關(guān)注公眾號(hào):撿田螺的小男孩"), executor); 
  8.         //supplyAsync的使用 
  9.         CompletableFuture<String> supplyFuture = CompletableFuture.supplyAsync(() -> { 
  10.                     System.out.print("supply,關(guān)注公眾號(hào):撿田螺的小男孩"); 
  11.                     return "撿田螺的小男孩"; }, executor); 
  12.         //runAsync的future沒有返回值,輸出null 
  13.         System.out.println(runFuture.join()); 
  14.         //supplyAsync的future,有返回值 
  15.         System.out.println(supplyFuture.join()); 
  16.         executor.shutdown(); // 線程池需要關(guān)閉 
  17.     } 
  18. //輸出 
  19. run,關(guān)注公眾號(hào):撿田螺的小男孩 
  20. null 
  21. supply,關(guān)注公眾號(hào):撿田螺的小男孩撿田螺的小男孩 

任務(wù)異步回調(diào)

1. thenRun/thenRunAsync

  1. public CompletableFuture<Void> thenRun(Runnable action); 
  2. public CompletableFuture<Void> thenRunAsync(Runnable action); 

CompletableFuture的thenRun方法,通俗點(diǎn)講就是,做完第一個(gè)任務(wù)后,再做第二個(gè)任務(wù)。某個(gè)任務(wù)執(zhí)行完成后,執(zhí)行回調(diào)方法;但是前后兩個(gè)任務(wù)沒有參數(shù)傳遞,第二個(gè)任務(wù)也沒有返回值

  1. public class FutureThenRunTest { 
  2.  
  3.     public static void main(String[] args) throws ExecutionException, InterruptedException { 
  4.  
  5.         CompletableFuture<String> orgFuture = CompletableFuture.supplyAsync( 
  6.                 ()->{ 
  7.                     System.out.println("先執(zhí)行第一個(gè)CompletableFuture方法任務(wù)"); 
  8.                     return "撿田螺的小男孩"
  9.                 } 
  10.         ); 
  11.  
  12.         CompletableFuture thenRunFuture = orgFuture.thenRun(() -> { 
  13.             System.out.println("接著執(zhí)行第二個(gè)任務(wù)"); 
  14.         }); 
  15.  
  16.         System.out.println(thenRunFuture.get()); 
  17.     } 
  18. //輸出 
  19. 先執(zhí)行第一個(gè)CompletableFuture方法任務(wù) 
  20. 接著執(zhí)行第二個(gè)任務(wù) 
  21. null 

thenRun 和thenRunAsync有什么區(qū)別呢?可以看下源碼哈:

  1. private static final Executor asyncPool = useCommonPool ? 
  2.       ForkJoinPool.commonPool() : new ThreadPerTaskExecutor(); 
  3.        
  4.   public CompletableFuture<Void> thenRun(Runnable action) { 
  5.       return uniRunStage(nullaction); 
  6.   } 
  7.  
  8.   public CompletableFuture<Void> thenRunAsync(Runnable action) { 
  9.       return uniRunStage(asyncPool, action); 
  10.   } 

如果你執(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線程池

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

2.thenAccept/thenAcceptAsync

CompletableFuture的thenAccept方法表示,第一個(gè)任務(wù)執(zhí)行完成后,執(zhí)行第二個(gè)回調(diào)方法任務(wù),會(huì)將該任務(wù)的執(zhí)行結(jié)果,作為入?yún)ⅲ瑐鬟f到回調(diào)方法中,但是回調(diào)方法是沒有返回值的。

  1. public class FutureThenAcceptTest { 
  2.  
  3.     public static void main(String[] args) throws ExecutionException, InterruptedException { 
  4.  
  5.         CompletableFuture<String> orgFuture = CompletableFuture.supplyAsync( 
  6.                 ()->{ 
  7.                     System.out.println("原始CompletableFuture方法任務(wù)"); 
  8.                     return "撿田螺的小男孩"
  9.                 } 
  10.         ); 
  11.  
  12.         CompletableFuture thenAcceptFuture = orgFuture.thenAccept((a) -> { 
  13.             if ("撿田螺的小男孩".equals(a)) { 
  14.                 System.out.println("關(guān)注了"); 
  15.             } 
  16.  
  17.             System.out.println("先考慮考慮"); 
  18.         }); 
  19.  
  20.         System.out.println(thenAcceptFuture.get()); 
  21.     } 

3. thenApply/thenApplyAsync

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

  1. public class FutureThenApplyTest { 
  2.  
  3.     public static void main(String[] args) throws ExecutionException, InterruptedException { 
  4.  
  5.         CompletableFuture<String> orgFuture = CompletableFuture.supplyAsync( 
  6.                 ()->{ 
  7.                     System.out.println("原始CompletableFuture方法任務(wù)"); 
  8.                     return "撿田螺的小男孩"
  9.                 } 
  10.         ); 
  11.  
  12.         CompletableFuture<String> thenApplyFuture = orgFuture.thenApply((a) -> { 
  13.             if ("撿田螺的小男孩".equals(a)) { 
  14.                 return "關(guān)注了"
  15.             } 
  16.  
  17.             return "先考慮考慮"
  18.         }); 
  19.  
  20.         System.out.println(thenApplyFuture.get()); 
  21.     } 
  22. //輸出 
  23. 原始CompletableFuture方法任務(wù) 
  24. 關(guān)注了 

4. exceptionally

CompletableFuture的exceptionally方法表示,某個(gè)任務(wù)執(zhí)行異常時(shí),執(zhí)行的回調(diào)方法;并且有拋出異常作為參數(shù),傳遞到回調(diào)方法。

  1. public class FutureExceptionTest { 
  2.  
  3.     public static void main(String[] args) throws ExecutionException, InterruptedException { 
  4.  
  5.         CompletableFuture<String> orgFuture = CompletableFuture.supplyAsync( 
  6.                 ()->{ 
  7.                     System.out.println("當(dāng)前線程名稱:" + Thread.currentThread().getName()); 
  8.                     throw new RuntimeException(); 
  9.                 } 
  10.         ); 
  11.  
  12.         CompletableFuture<String> exceptionFuture = orgFuture.exceptionally((e) -> { 
  13.             e.printStackTrace(); 
  14.             return "你的程序異常啦"
  15.         }); 
  16.  
  17.         System.out.println(exceptionFuture.get()); 
  18.     } 
  19. //輸出 
  20. 當(dāng)前線程名稱:ForkJoinPool.commonPool-worker-1 
  21. java.util.concurrent.CompletionException: java.lang.RuntimeException 
  22.  at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273) 
  23.  at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280) 
  24.  at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1592) 
  25.  at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582) 
  26.  at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289) 
  27.  at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056) 
  28.  at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692) 
  29.  at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157) 
  30. Caused by: java.lang.RuntimeException 
  31.  at cn.eovie.future.FutureWhenTest.lambda$main$0(FutureWhenTest.java:13) 
  32.  at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590) 
  33.  ... 5 more 
  34. 你的程序異常啦 

5. whenComplete方法

CompletableFuture的whenComplete方法表示,某個(gè)任務(wù)執(zhí)行完成后,執(zhí)行的回調(diào)方法,無返回值;并且whenComplete方法返回的CompletableFuture的result是上個(gè)任務(wù)的結(jié)果。

  1. public class FutureWhenTest { 
  2.  
  3.     public static void main(String[] args) throws ExecutionException, InterruptedException { 
  4.  
  5.         CompletableFuture<String> orgFuture = CompletableFuture.supplyAsync( 
  6.                 ()->{ 
  7.                     System.out.println("當(dāng)前線程名稱:" + Thread.currentThread().getName()); 
  8.                     try { 
  9.                         Thread.sleep(2000L); 
  10.                     } catch (InterruptedException e) { 
  11.                         e.printStackTrace(); 
  12.                     } 
  13.                     return "撿田螺的小男孩"
  14.                 } 
  15.         ); 
  16.  
  17.         CompletableFuture<String> rstFuture = orgFuture.whenComplete((a, throwable) -> { 
  18.             System.out.println("當(dāng)前線程名稱:" + Thread.currentThread().getName()); 
  19.             System.out.println("上個(gè)任務(wù)執(zhí)行完啦,還把" + a + "傳過來"); 
  20.             if ("撿田螺的小男孩".equals(a)) { 
  21.                 System.out.println("666"); 
  22.             } 
  23.             System.out.println("233333"); 
  24.         }); 
  25.  
  26.         System.out.println(rstFuture.get()); 
  27.     } 
  28. //輸出 
  29. 當(dāng)前線程名稱:ForkJoinPool.commonPool-worker-1 
  30. 當(dāng)前線程名稱:ForkJoinPool.commonPool-worker-1 
  31. 上個(gè)任務(wù)執(zhí)行完啦,還把撿田螺的小男孩傳過來 
  32. 666 
  33. 233333 
  34. 撿田螺的小男孩 

6. handle方法

CompletableFuture的handle方法表示,某個(gè)任務(wù)執(zhí)行完成后,執(zhí)行回調(diào)方法,并且是有返回值的;并且handle方法返回的CompletableFuture的result是回調(diào)方法執(zhí)行的結(jié)果。

  1. public class FutureHandlerTest { 
  2.  
  3.     public static void main(String[] args) throws ExecutionException, InterruptedException { 
  4.  
  5.         CompletableFuture<String> orgFuture = CompletableFuture.supplyAsync( 
  6.                 ()->{ 
  7.                     System.out.println("當(dāng)前線程名稱:" + Thread.currentThread().getName()); 
  8.                     try { 
  9.                         Thread.sleep(2000L); 
  10.                     } catch (InterruptedException e) { 
  11.                         e.printStackTrace(); 
  12.                     } 
  13.                     return "撿田螺的小男孩"
  14.                 } 
  15.         ); 
  16.  
  17.         CompletableFuture<String> rstFuture = orgFuture.handle((a, throwable) -> { 
  18.  
  19.             System.out.println("上個(gè)任務(wù)執(zhí)行完啦,還把" + a + "傳過來"); 
  20.             if ("撿田螺的小男孩".equals(a)) { 
  21.                 System.out.println("666"); 
  22.                 return "關(guān)注了"
  23.             } 
  24.             System.out.println("233333"); 
  25.             return null
  26.         }); 
  27.  
  28.         System.out.println(rstFuture.get()); 
  29.     } 
  30. //輸出 
  31. 當(dāng)前線程名稱:ForkJoinPool.commonPool-worker-1 
  32. 上個(gè)任務(wù)執(zhí)行完啦,還把撿田螺的小男孩傳過來 
  33. 666 
  34. 關(guān)注了 

多個(gè)任務(wù)組合處理

AND組合關(guān)系

thenCombine / thenAcceptBoth / runAfterBoth都表示:將兩個(gè)CompletableFuture組合起來,只有這兩個(gè)都正常執(zhí)行完了,才會(huì)執(zhí)行某個(gè)任務(wù)。

區(qū)別在于:

  • thenCombine:會(huì)將兩個(gè)任務(wù)的執(zhí)行結(jié)果作為方法入?yún)ⅲ瑐鬟f到指定方法中,且有返回值
  • thenAcceptBoth: 會(huì)將兩個(gè)任務(wù)的執(zhí)行結(jié)果作為方法入?yún)ⅲ瑐鬟f到指定方法中,且無返回值
  • runAfterBoth 不會(huì)把執(zhí)行結(jié)果當(dāng)做方法入?yún)ⅲ覜]有返回值。
  1. public class ThenCombineTest { 
  2.  
  3.     public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException { 
  4.  
  5.         CompletableFuture<String> first = CompletableFuture.completedFuture("第一個(gè)異步任務(wù)"); 
  6.         ExecutorService executor = Executors.newFixedThreadPool(10); 
  7.         CompletableFuture<String> future = CompletableFuture 
  8.                 //第二個(gè)異步任務(wù) 
  9.                 .supplyAsync(() -> "第二個(gè)異步任務(wù)", executor) 
  10.                 // (w, s) -> System.out.println(s) 是第三個(gè)任務(wù) 
  11.                 .thenCombineAsync(first, (s, w) -> { 
  12.                     System.out.println(w); 
  13.                     System.out.println(s); 
  14.                     return "兩個(gè)異步任務(wù)的組合"
  15.                 }, executor); 
  16.         System.out.println(future.join()); 
  17.         executor.shutdown(); 
  18.  
  19.     } 
  20. //輸出 
  21. 第一個(gè)異步任務(wù) 
  22. 第二個(gè)異步任務(wù) 
  23. 兩個(gè)異步任務(wù)的組合 

OR 組合的關(guān)系

applyToEither / acceptEither / runAfterEither 都表示:將兩個(gè)CompletableFuture組合起來,只要其中一個(gè)執(zhí)行完了,就會(huì)執(zhí)行某個(gè)任務(wù)。

區(qū)別在于:

  • applyToEither:會(huì)將已經(jīng)執(zhí)行完成的任務(wù),作為方法入?yún)ⅲ瑐鬟f到指定方法中,且有返回值
  • acceptEither: 會(huì)將已經(jīng)執(zhí)行完成的任務(wù),作為方法入?yún)ⅲ瑐鬟f到指定方法中,且無返回值
  • runAfterEither:不會(huì)把執(zhí)行結(jié)果當(dāng)做方法入?yún)ⅲ覜]有返回值。
  1. public class AcceptEitherTest { 
  2.     public static void main(String[] args) { 
  3.         //第一個(gè)異步任務(wù),休眠2秒,保證它執(zhí)行晚點(diǎn) 
  4.         CompletableFuture<String> first = CompletableFuture.supplyAsync(()->{ 
  5.             try{ 
  6.  
  7.                 Thread.sleep(2000L); 
  8.                 System.out.println("執(zhí)行完第一個(gè)異步任務(wù)");} 
  9.                 catch (Exception e){ 
  10.                     return "第一個(gè)任務(wù)異常"
  11.                 } 
  12.             return "第一個(gè)異步任務(wù)"
  13.         }); 
  14.         ExecutorService executor = Executors.newSingleThreadExecutor(); 
  15.         CompletableFuture<Void> future = CompletableFuture 
  16.                 //第二個(gè)異步任務(wù) 
  17.                 .supplyAsync(() -> { 
  18.                             System.out.println("執(zhí)行完第二個(gè)任務(wù)"); 
  19.                             return "第二個(gè)任務(wù)";} 
  20.                 , executor) 
  21.                 //第三個(gè)任務(wù) 
  22.                 .acceptEitherAsync(first, System.out::println, executor); 
  23.  
  24.         executor.shutdown(); 
  25.     } 
  26. //輸出 
  27. 執(zhí)行完第二個(gè)任務(wù) 
  28. 第二個(gè)任務(wù) 

AllOf

所有任務(wù)都執(zhí)行完成后,才執(zhí)行 allOf返回的CompletableFuture。如果任意一個(gè)任務(wù)異常,allOf的CompletableFuture,執(zhí)行g(shù)et方法,會(huì)拋出異常

  1. public class allOfFutureTest { 
  2.     public static void main(String[] args) throws ExecutionException, InterruptedException { 
  3.  
  4.         CompletableFuture<Void> a = CompletableFuture.runAsync(()->{ 
  5.             System.out.println("我執(zhí)行完了"); 
  6.         }); 
  7.         CompletableFuture<Void> b = CompletableFuture.runAsync(() -> { 
  8.             System.out.println("我也執(zhí)行完了"); 
  9.         }); 
  10.         CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(a, b).whenComplete((m,k)->{ 
  11.             System.out.println("finish"); 
  12.         }); 
  13.     } 
  14. //輸出 
  15. 我執(zhí)行完了 
  16. 我也執(zhí)行完了 
  17. finish 

AnyOf

任意一個(gè)任務(wù)執(zhí)行完,就執(zhí)行anyOf返回的CompletableFuture。如果執(zhí)行的任務(wù)異常,anyOf的CompletableFuture,執(zhí)行g(shù)et方法,會(huì)拋出異常

  1. public class AnyOfFutureTest { 
  2.     public static void main(String[] args) throws ExecutionException, InterruptedException { 
  3.  
  4.         CompletableFuture<Void> a = CompletableFuture.runAsync(()->{ 
  5.             try { 
  6.                 Thread.sleep(3000L); 
  7.             } catch (InterruptedException e) { 
  8.                 e.printStackTrace(); 
  9.             } 
  10.             System.out.println("我執(zhí)行完了"); 
  11.         }); 
  12.         CompletableFuture<Void> b = CompletableFuture.runAsync(() -> { 
  13.             System.out.println("我也執(zhí)行完了"); 
  14.         }); 
  15.         CompletableFuture<Object> anyOfFuture = CompletableFuture.anyOf(a, b).whenComplete((m,k)->{ 
  16.             System.out.println("finish"); 
  17. //            return "撿田螺的小男孩"
  18.         }); 
  19.         anyOfFuture.join(); 
  20.     } 
  21. //輸出 
  22. 我也執(zhí)行完了 
  23. finish 

thenCompose

thenCompose方法會(huì)在某個(gè)任務(wù)執(zhí)行完成后,將該任務(wù)的執(zhí)行結(jié)果,作為方法入?yún)?去執(zhí)行指定的方法。該方法會(huì)返回一個(gè)新的CompletableFuture實(shí)例

  • 如果該CompletableFuture實(shí)例的result不為null,則返回一個(gè)基于該result新的CompletableFuture實(shí)例;
  • 如果該CompletableFuture實(shí)例為null,然后就執(zhí)行這個(gè)新任務(wù)
  1. public class ThenComposeTest { 
  2.     public static void main(String[] args) throws ExecutionException, InterruptedException { 
  3.  
  4.         CompletableFuture<String> f = CompletableFuture.completedFuture("第一個(gè)任務(wù)"); 
  5.         //第二個(gè)異步任務(wù) 
  6.         ExecutorService executor = Executors.newSingleThreadExecutor(); 
  7.         CompletableFuture<String> future = CompletableFuture 
  8.                 .supplyAsync(() -> "第二個(gè)任務(wù)", executor) 
  9.                 .thenComposeAsync(data -> { 
  10.                     System.out.println(data); return f; //使用第一個(gè)任務(wù)作為返回 
  11.                 }, executor); 
  12.         System.out.println(future.join()); 
  13.         executor.shutdown(); 
  14.  
  15.     } 
  16. //輸出 
  17. 第二個(gè)任務(wù) 
  18. 第一個(gè)任務(wù) 

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

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

1. Future需要獲取返回值,才能獲取異常信息

  1. ExecutorService executorService = new ThreadPoolExecutor(5, 10, 5L, 
  2.     TimeUnit.SECONDS, new ArrayBlockingQueue<>(10)); 
  3. CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> { 
  4.       int a = 0; 
  5.       int b = 666; 
  6.       int c = b / a; 
  7.       return true
  8.    },executorService).thenAccept(System.out::println); 
  9.     
  10.  //如果不加 get()方法這一行,看不到異常信息 
  11.  //future.get(); 

Future需要獲取返回值,才能獲取到異常信息。如果不加 get()/join()方法,看不到異常信息。小伙伴們使用的時(shí)候,注意一下哈,考慮是否加try...catch...或者使用exceptionally方法。

2. CompletableFuture的get()方法是阻塞的。

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

  1. //反例 
  2.  CompletableFuture.get(); 
  3. //正例 
  4. CompletableFuture.get(5, TimeUnit.SECONDS); 

3. 默認(rèn)線程池的注意點(diǎn)

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

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

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

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

參考資料

[1]Java8 CompletableFuture 用法全解: https://blog.csdn.net/qq_31865983/article/details/106137777

[2]基礎(chǔ)篇:異步編程不會(huì)?我教你啊!: https://juejin.cn/post/6902655550031413262#heading-5

[3]CompletableFuture get方法一直阻塞或拋出TimeoutException: https://blog.csdn.net/xiaolyuh123/article/details/85023269

[4]編程老司機(jī)帶你玩轉(zhuǎn) CompletableFuture 異步編程: https://zhuanlan.zhihu.com/p/111841508

[5]解決CompletableFuture異常阻塞: https://blog.csdn.net/weixin_42742643/article/details/111638260

本文轉(zhuǎn)載自微信公眾號(hào)「撿田螺的小男孩」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系撿田螺的小男孩公眾號(hào)。

 

責(zé)任編輯:武曉燕 來源: 撿田螺的小男孩
相關(guān)推薦

2024-04-18 08:20:27

Java 8編程工具

2022-07-08 14:14:04

并發(fā)編程異步編程

2021-02-21 14:35:29

Java 8異步編程

2020-05-29 07:20:00

Java8異步編程源碼解讀

2024-03-06 08:13:33

FutureJDKCallable

2016-09-07 20:43:36

Javascript異步編程

2025-02-06 16:51:30

2025-02-28 09:20:00

Future開發(fā)代碼

2017-12-21 15:48:11

JavaCompletable

2024-12-26 12:59:39

2023-07-19 08:03:05

Future異步JDK

2024-10-14 08:29:14

異步編程任務(wù)

2024-08-06 09:43:54

Java 8工具編程

2023-11-06 08:14:51

Go語(yǔ)言Context

2015-06-16 11:06:42

JavaCompletable

2024-04-30 11:11:33

aiohttp模塊編程

2013-04-01 15:38:54

異步編程異步編程模型

2025-11-13 08:22:03

2023-11-24 16:13:05

C++編程

2025-04-30 01:50:00

C#異步編程
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

国产大片中文字幕| 欧美三级午夜理伦三级富婆| 色婷婷综合视频| 久久久青草婷婷精品综合日韩| 在线欧美小视频| 亚洲欧美日韩精品久久久| 国产精品久久无码一三区| 久久av综合| 欧美一级片在线| 哪个网站能看毛片| 在线网址91| 久久精品男人天堂av| 欧美在线激情网| 中文字幕无码日韩专区免费| 欧美成人专区| 日韩亚洲欧美一区| 国产一级不卡毛片| 精品日韩av| 国产精品区一区二区三区| 国产精品毛片va一区二区三区| 免费在线观看黄色av| 免费久久精品| 欧美狂野另类xxxxoooo| 无码精品a∨在线观看中文| 老司机午夜在线| 久久久精品影视| 国产精品日韩精品| 黄色片视频网站| 久久久久久久久久久久久久久久久久| 欧美一区二区久久久| 日韩欧美视频免费在线观看| 91大神xh98hx在线播放| 91丨porny丨国产入口| 91成人在线看| 一二三四区视频| 日韩va亚洲va欧美va久久| 性色av香蕉一区二区| 国产大学生自拍| 久久久久久久久久久妇女| 精品久久久三级丝袜| 波多野结衣乳巨码无在线| 中文字幕伦理免费在线视频| 中文字幕一区不卡| 日韩动漫在线观看| 你懂的视频在线| 精品中文字幕一区二区| 欧美黄网免费在线观看| 精品无码久久久久成人漫画| 国产精品伦理久久久久久| 国产一区二区三区毛片| 91精品国自产在线| 国产精品极品在线观看| 欧美日韩中文字幕在线视频| 宅男噜噜99国产精品观看免费| jlzzjlzzjlzz亚洲人| 亚洲欧美日韩国产综合精品二区| 最新91在线视频| 免费看的黄色网| 精品国产精品| 中文字幕成人在线| 特黄一区二区三区| 欧美岛国激情| 久久在线视频在线| 青青草原国产视频| 在线观看视频日韩| 欧美一区二区.| 国产精品白嫩白嫩大学美女| 欧美日一区二区在线观看| 久久91亚洲精品中文字幕| 久久国产在线视频| 日韩欧美字幕| 久久这里只有精品99| 久久久久久久国产视频| 国产欧美另类| 国产精品久久久久久超碰 | 午夜在线视频免费观看| 欧美黑人激情| 夜色激情一区二区| 国内精品在线观看视频| 伊人久久视频| 亚洲福利视频三区| 丰满人妻中伦妇伦精品app| 人人鲁人人莫人人爱精品| 欧美精三区欧美精三区| 亚洲成a人片在线www| 小说区图片区色综合区| 在线观看日韩欧美| 欧美成人精品欧美一级私黄| 亚洲精品97| 国内精品国产三级国产在线专| 91成人福利视频| 1024精品一区二区三区| 国产成人一区二区在线| 久久人妻免费视频| 另类综合日韩欧美亚洲| 国产色综合一区二区三区| 国产youjizz在线| 日韩一区欧美小说| 中文字幕日本最新乱码视频| 日日狠狠久久| 亚洲精品狠狠操| 中文在线永久免费观看| 国产极品模特精品一二| 在线播放国产精品| 国产午夜小视频| 亚洲视频免费| 国产精品第一视频| 蜜桃视频久久一区免费观看入口| 成人综合激情网| 日韩精品无码一区二区三区| 色呦呦视频在线观看| 在线视频你懂得一区二区三区| 国模杨依粉嫩蝴蝶150p| 欧美日韩免费观看视频| 精品国产青草久久久久福利| 91成人精品一区二区| 中文亚洲字幕| 99re在线播放| 婷婷成人激情| 在线中文字幕一区二区| 成人性生交免费看| 日韩高清电影免费| 欧美激情三级免费| a级片在线视频| 国产精品乱子久久久久| www.欧美日本| 99久久久成人国产精品| 一区二区在线视频播放| 美国精品一区二区| 欧美福利视频| 91免费看国产| 欧美私人网站| 欧美三级三级三级爽爽爽| 熟妇高潮精品一区二区三区| 国产一区久久| 肥熟一91porny丨九色丨| 老司机午夜在线| 欧美精品aⅴ在线视频| 无码少妇一区二区| 日韩极品在线观看| 蜜桃在线一区二区三区精品| 极品美鲍一区| 日韩电影中文字幕一区| 欧美成人精品欧美一级乱黄| 成人av电影免费在线播放| av一区二区三区免费观看| 91嫩草国产线观看亚洲一区二区| 亚洲第一免费播放区| 欧美精品久久久久性色| 成人综合在线视频| 国产素人在线观看| 在线成人动漫av| 日韩av片永久免费网站| 国产一级在线| 欧美三级电影在线看| 国产在线免费av| 亚洲毛片一区| 美乳视频一区二区| 毛片久久久久久| 69视频在线观看| 欧美日韩国产一级片| 国产女主播在线播放| 残酷重口调教一区二区| 国产精品视频xxx| 美女av在线播放| 欧美精品aⅴ在线视频| 亚洲色婷婷一区二区三区| 丰满岳乱妇一区二区三区| 草b视频在线观看| 日韩激情毛片| 国产精品永久免费在线| 日本福利在线观看| 在线观看网站黄不卡| 欧美色视频一区二区三区在线观看| 香蕉国产精品偷在线观看不卡| 91成人在线看| 男人天堂视频在线观看| 在线观看精品国产视频| 国产成年妇视频| 五月综合激情日本mⅴ| 精品成人av一区二区三区| 男人操女人的视频在线观看欧美| 久久日韩精品| 另类中文字幕国产精品| 久久天天躁狠狠躁夜夜躁| 好吊色一区二区三区| 亚洲综合精品自拍| 亚洲av综合一区二区| 另类图片国产| 女女同性女同一区二区三区按摩| 羞羞视频在线观看一区二区| 久久久久久国产精品| 韩国中文字幕2020精品| 色八戒一区二区三区| 三级影片在线看| 久久嫩草精品久久久精品| 亚洲欧美日韩综合网| 99国产精品视频免费观看一公开 | 久久综合精品国产一区二区三区| 少妇高潮喷水在线观看| 欧美一二区在线观看| 91九色极品视频| 日韩毛片一区| 97国产在线视频| 黄色网址在线免费播放| 日韩成人激情在线| 国产三级伦理片| 欧美亚日韩国产aⅴ精品中极品| 最新国产成人av网站网址麻豆| 日本人添下边视频免费| 蜜臀精品一区二区三区在线观看| 婷婷亚洲婷婷综合色香五月| 国产福利一区二区三区在线播放| 最新国产成人av网站网址麻豆| 97精品人妻一区二区三区香蕉| 亚洲精品免费视频| 性欧美精品男男| www久久久久| 久久性爱视频网站| 国产成人综合在线观看| 91女神在线观看| 欧美日韩午夜| 在线视频不卡一区二区| 男男gay无套免费视频欧美| 懂色av一区二区三区在线播放| 在线观看v片| 欧美黑人巨大精品一区二区| 尤物视频在线免费观看| 亚洲人成电影在线播放| 日韩在线免费播放| 精品国产乱码久久久久久影片| 可以在线观看av的网站| 亚洲自拍偷拍综合| 欧美三级在线免费观看| 亚洲欧美日韩电影| 91精品国产高清久久久久久久久| 国产大片aaa| 亚洲精品中文在线影院| 日本二区三区视频| 国产精品久久一级| 超碰人人干人人| 国产精品视频你懂的| av免费播放网站| 中文字幕的久久| 亚洲女同二女同志奶水| 国产精品免费看片| 艳妇乳肉豪妇荡乳xxx| 久久久久久穴| www.国产在线播放| 在线精品观看| 男女视频网站在线观看| 97视频热人人精品免费| 一区二区三区四区欧美| 日韩三级毛片| 欧美理论一区二区| 久操成人av| 亚洲国产精品久久久久婷婷老年| jizz性欧美2| 国产伦一区二区三区色一情| 在线免费成人| 91av免费看| 91精品尤物| 久久精品午夜一区二区福利| 欧美影院在线| 狠狠色综合一区二区| 曰本一区二区三区视频| 午夜欧美一区二区三区免费观看| 国产精品网站在线看| 久久手机视频| 男女全黄做爰文章| 激情五月婷婷综合| 无码人妻aⅴ一区二区三区玉蒲团| 久久一区激情| 九九热99视频| 国产99久久精品| 女同毛片一区二区三区| 中文在线免费一区三区高中清不卡| 亚洲蜜桃精久久久久久久久久久久| 久久国产尿小便嘘嘘| 97免费公开视频| 国产在线精品一区二区夜色| 中文字幕网av| 国产麻豆精品theporn| 男女一区二区三区| 亚洲国产成人在线| 欧美三级视频网站| 亚洲激情av在线| 无码人妻一区二区三区免费| 4438亚洲最大| 青青青手机在线视频观看| 日韩中文字幕在线观看| 蜜桃麻豆影像在线观看| 成人美女免费网站视频| 美日韩黄色大片| 欧美爱爱视频网站| 午夜亚洲性色福利视频| 无套内谢丰满少妇中文字幕| 久久综合精品国产一区二区三区| 18禁裸乳无遮挡啪啪无码免费| 99久久久免费精品国产一区二区 | 欧美男人亚洲天堂| 3atv一区二区三区| av手机免费看| 亚洲欧美另类自拍| 手机av免费在线| 国内揄拍国内精品少妇国语| 黄页免费欧美| 免费一区二区三区在在线视频| 精品中文一区| www.日本在线视频| 久久99精品久久久久久国产越南| 熟妇无码乱子成人精品| 国产日产欧美精品一区二区三区| 欧美三级视频网站| 婷婷国产v国产偷v亚洲高清| 四虎成人在线观看| 欧美性大战久久| 国产免费黄色网址| 国产午夜精品全部视频在线播放| 在线观看精品一区二区三区| 97成人在线视频| av成人资源网| 男女啪啪免费观看| 麻豆国产精品一区二区三区| 超级砰砰砰97免费观看最新一期 | 亚洲成色精品| 国内自拍第二页| 国产精品三级av| 久久久精品高清| 羞羞网站在线看| 2019中文字幕在线观看| 浪潮色综合久久天堂| 国内精品久久国产| 日韩欧美1区| 欧美一级裸体视频| www亚洲一区| www.欧美色| 亚洲人午夜精品免费| 成人性教育av免费网址| 久久精品久久精品国产大片| 99精品热6080yy久久| 在线天堂www在线国语对白| 欧美国产综合一区二区| 无码人妻一区二区三区免费| 亚洲免费一级电影| 免费看av不卡| 日韩欧美精品在线不卡| 日韩av一区二| 欧美激情视频二区| 亚洲一二三四在线观看| 一区二区三区亚洲视频| 日韩一级黄色av| 日韩高清在线观看一区二区| 国产人妻人伦精品| 成人午夜免费av| 黄网在线观看视频| 亚洲欧美一区二区三区四区| 调教一区二区| 国产精品综合不卡av| 999精品在线| 亚洲天堂小视频| 精品国产老师黑色丝袜高跟鞋| 国产三级精品在线观看| 久久97久久97精品免视看| 加勒比色老久久爱综合网| 欧美三级午夜理伦三级| 国产精品全国免费观看高清 | 国产欧美精品| 波多野吉衣中文字幕| 亚洲福利视频三区| 亚洲av成人无码久久精品老人| 欧美日本黄视频| 美女精品视频在线| 亚洲熟妇无码一区二区三区导航| 国产精品一区二区果冻传媒| 毛片久久久久久| 精品国产免费人成在线观看| 吉吉日韩欧美| 樱花www成人免费视频| 粉嫩av亚洲一区二区图片| 欧美特级一级片| 亚洲精品第一页| 国产91欧美| 欧美一级视频免费看| 国产网红主播福利一区二区| 日本在线观看天堂男亚洲| 日韩超碰人人爽人人做人人添| 8x8ⅹ国产精品一区二区二区| 精品一区二区三区影院在线午夜 | 亚洲免费成人网| 欧美亚洲国产日本| 亚洲精品一级二级三级| 在线视频观看91| 午夜成人在线视频| 天天在线女人的天堂视频| 国产成人福利视频| 亚洲一级一区| 国产三级aaa| 亚洲免费一在线| 亚洲视频一起|