成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

異步編程利器:CompletableFuture詳解

開發 項目管理
最近剛好使用CompeletableFuture優化了項目中的代碼,所以跟大家一起學習CompletableFuture。

[[403915]]

前言

最近剛好使用CompeletableFuture優化了項目中的代碼,所以跟大家一起學習CompletableFuture。

一個例子回顧 Future

因為CompletableFuture實現了Future接口,我們先來回顧Future吧。

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

來看個簡單例子吧,假設我們有兩個任務服務,一個查詢用戶基本信息,一個是查詢用戶勛章信息。如下,

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

接下來,我們來演示下,在主線程中是如何使用Future來進行異步調用的。

  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.         //調用用戶服務獲取用戶基本信息 
  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); //模擬主線程其它操作耗時 
  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();//獲取個人信息結果 
  32.         MedalInfo medalInfo = medalInfoFutureTask.get();//獲取勛章信息結果 
  33.  
  34.         System.out.println("總共用時" + (System.currentTimeMillis() - startTime) + "ms"); 
  35.     } 
  36.      

運行結果:

  1. 總共用時806ms 

如果我們不使用Future進行并行異步調用,而是在主線程串行進行的話,耗時大約為300+500+300 = 1100 ms。可以發現,future+線程池異步配合,提高了程序的執行效率。

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

  • Future.get() 就是阻塞調用,在線程獲取結果之前get方法會一直阻塞。
  • Future提供了一個isDone方法,可以在程序中輪詢這個方法查詢執行結果。

阻塞的方式和異步編程的設計理念相違背,而輪詢的方式會耗費無謂的CPU資源。因此,JDK8設計出CompletableFuture。CompletableFuture提供了一種觀察者模式類似的機制,可以讓任務執行完成后通知監聽的一方。

一個例子走進CompletableFuture

我們還是基于以上Future的例子,改用CompletableFuture 來實現

  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.         //調用用戶服務獲取用戶基本信息 
  11.         CompletableFuture<UserInfo> completableUserInfoFuture = CompletableFuture.supplyAsync(() -> userInfoService.getUserInfo(userId)); 
  12.  
  13.         Thread.sleep(300); //模擬主線程其它操作耗時 
  14.  
  15.         CompletableFuture<MedalInfo> completableMedalInfoFuture = CompletableFuture.supplyAsync(() -> medalService.getMedalInfo(userId));  
  16.  
  17.         UserInfo userInfo = completableUserInfoFuture.get(2,TimeUnit.SECONDS);//獲取個人信息結果 
  18.         MedalInfo medalInfo = completableMedalInfoFuture.get();//獲取勛章信息結果 
  19.         System.out.println("總共用時" + (System.currentTimeMillis() - startTime) + "ms"); 
  20.  
  21.     } 

可以發現,使用CompletableFuture,代碼簡潔了很多。CompletableFuture的supplyAsync方法,提供了異步執行的功能,線程池也不用單獨創建了。實際上,它CompletableFuture使用了默認線程池是ForkJoinPool.commonPool。

CompletableFuture提供了幾十種方法,輔助我們的異步任務場景。這些方法包括創建異步任務、任務異步回調、多個任務組合處理等方面。我們一起來學習吧

CompletableFuture使用場景

創建異步任務

CompletableFuture創建異步任務,一般有supplyAsync和runAsync兩個方法

創建異步任務

  • supplyAsync執行CompletableFuture任務,支持返回值
  • runAsync執行CompletableFuture任務,沒有返回值。

supplyAsync方法

//使用默認內置線程池ForkJoinPool.commonPool(),根據supplier構建執行任務

  1. //使用默認內置線程池ForkJoinPool.commonPool(),根據supplier構建執行任務 
  2. public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) 
  3. //自定義線程,根據supplier構建執行任務 
  4. public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor) 

runAsync方法

  1. //使用默認內置線程池ForkJoinPool.commonPool(),根據runnable構建執行任務 
  2. public static CompletableFuture<Void> runAsync(Runnable runnable)  
  3. //自定義線程,根據runnable構建執行任務 
  4. public static CompletableFuture<Void> runAsync(Runnable runnable,  Executor executor) 

實例代碼如下:

  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,關注公眾號:撿田螺的小男孩"), executor); 
  8.         //supplyAsync的使用 
  9.         CompletableFuture<String> supplyFuture = CompletableFuture.supplyAsync(() -> { 
  10.                     System.out.print("supply,關注公眾號:撿田螺的小男孩"); 
  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(); // 線程池需要關閉 
  17.     } 
  18. //輸出 
  19. run,關注公眾號:撿田螺的小男孩 
  20. null 
  21. supply,關注公眾號:撿田螺的小男孩撿田螺的小男孩 

任務異步回調

1. thenRun/thenRunAsync

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

CompletableFuture的thenRun方法,通俗點講就是,做完第一個任務后,再做第二個任務。某個任務執行完成后,執行回調方法;但是前后兩個任務沒有參數傳遞,第二個任務也沒有返回值

  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("先執行第一個CompletableFuture方法任務"); 
  8.                     return "撿田螺的小男孩"
  9.                 } 
  10.         ); 
  11.  
  12.         CompletableFuture thenRunFuture = orgFuture.thenRun(() -> { 
  13.             System.out.println("接著執行第二個任務"); 
  14.         }); 
  15.  
  16.         System.out.println(thenRunFuture.get()); 
  17.     } 
  18. //輸出 
  19. 先執行第一個CompletableFuture方法任務 
  20. 接著執行第二個任務 
  21. null 

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

  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.   } 

如果你執行第一個任務的時候,傳入了一個自定義線程池:

  • 調用thenRun方法執行第二個任務時,則第二個任務和第一個任務是共用同一個線程池。
  • 調用thenRunAsync執行第二個任務時,則第一個任務使用的是你自己傳入的線程池,第二個任務使用的是ForkJoin線程池

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

2.thenAccept/thenAcceptAsync

CompletableFuture的thenAccept方法表示,第一個任務執行完成后,執行第二個回調方法任務,會將該任務的執行結果,作為入參,傳遞到回調方法中,但是回調方法是沒有返回值的。

  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方法任務"); 
  8.                     return "撿田螺的小男孩"
  9.                 } 
  10.         ); 
  11.  
  12.         CompletableFuture thenAcceptFuture = orgFuture.thenAccept((a) -> { 
  13.             if ("撿田螺的小男孩".equals(a)) { 
  14.                 System.out.println("關注了"); 
  15.             } 
  16.  
  17.             System.out.println("先考慮考慮"); 
  18.         }); 
  19.  
  20.         System.out.println(thenAcceptFuture.get()); 
  21.     } 

3. thenApply/thenApplyAsync

CompletableFuture的thenApply方法表示,第一個任務執行完成后,執行第二個回調方法任務,會將該任務的執行結果,作為入參,傳遞到回調方法中,并且回調方法是有返回值的。

  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方法任務"); 
  8.                     return "撿田螺的小男孩"
  9.                 } 
  10.         ); 
  11.  
  12.         CompletableFuture<String> thenApplyFuture = orgFuture.thenApply((a) -> { 
  13.             if ("撿田螺的小男孩".equals(a)) { 
  14.                 return "關注了"
  15.             } 
  16.  
  17.             return "先考慮考慮"
  18.         }); 
  19.  
  20.         System.out.println(thenApplyFuture.get()); 
  21.     } 
  22. //輸出 
  23. 原始CompletableFuture方法任務 
  24. 關注了 

4. exceptionally

CompletableFuture的exceptionally方法表示,某個任務執行異常時,執行的回調方法;并且有拋出異常作為參數,傳遞到回調方法。

  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("當前線程名稱:" + 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. 當前線程名稱: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方法表示,某個任務執行完成后,執行的回調方法,無返回值;并且whenComplete方法返回的CompletableFuture的result是上個任務的結果。

  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("當前線程名稱:" + 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("當前線程名稱:" + Thread.currentThread().getName()); 
  19.             System.out.println("上個任務執行完啦,還把" + 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. 當前線程名稱:ForkJoinPool.commonPool-worker-1 
  30. 當前線程名稱:ForkJoinPool.commonPool-worker-1 
  31. 上個任務執行完啦,還把撿田螺的小男孩傳過來 
  32. 666 
  33. 233333 
  34. 撿田螺的小男孩 

6. handle方法

CompletableFuture的handle方法表示,某個任務執行完成后,執行回調方法,并且是有返回值的;并且handle方法返回的CompletableFuture的result是回調方法執行的結果。

  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("當前線程名稱:" + 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("上個任務執行完啦,還把" + a + "傳過來"); 
  20.             if ("撿田螺的小男孩".equals(a)) { 
  21.                 System.out.println("666"); 
  22.                 return "關注了"
  23.             } 
  24.             System.out.println("233333"); 
  25.             return null
  26.         }); 
  27.  
  28.         System.out.println(rstFuture.get()); 
  29.     } 
  30. //輸出 
  31. 當前線程名稱:ForkJoinPool.commonPool-worker-1 
  32. 上個任務執行完啦,還把撿田螺的小男孩傳過來 
  33. 666 
  34. 關注了 

多個任務組合處理

AND組合關系

thenCombine / thenAcceptBoth / runAfterBoth都表示:將兩個CompletableFuture組合起來,只有這兩個都正常執行完了,才會執行某個任務。

區別在于:

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

OR 組合的關系

applyToEither / acceptEither / runAfterEither 都表示:將兩個CompletableFuture組合起來,只要其中一個執行完了,就會執行某個任務。

區別在于:

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

AllOf

所有任務都執行完成后,才執行 allOf返回的CompletableFuture。如果任意一個任務異常,allOf的CompletableFuture,執行get方法,會拋出異常

  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("我執行完了"); 
  6.         }); 
  7.         CompletableFuture<Void> b = CompletableFuture.runAsync(() -> { 
  8.             System.out.println("我也執行完了"); 
  9.         }); 
  10.         CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(a, b).whenComplete((m,k)->{ 
  11.             System.out.println("finish"); 
  12.         }); 
  13.     } 
  14. //輸出 
  15. 我執行完了 
  16. 我也執行完了 
  17. finish 

AnyOf

任意一個任務執行完,就執行anyOf返回的CompletableFuture。如果執行的任務異常,anyOf的CompletableFuture,執行get方法,會拋出異常

  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("我執行完了"); 
  11.         }); 
  12.         CompletableFuture<Void> b = CompletableFuture.runAsync(() -> { 
  13.             System.out.println("我也執行完了"); 
  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. 我也執行完了 
  23. finish 

thenCompose

thenCompose方法會在某個任務執行完成后,將該任務的執行結果,作為方法入參,去執行指定的方法。該方法會返回一個新的CompletableFuture實例

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

CompletableFuture使用有哪些注意點

CompletableFuture 使我們的異步編程更加便利的、代碼更加優雅的同時,我們也要關注下它,使用的一些注意點。

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()方法,看不到異常信息。小伙伴們使用的時候,注意一下哈,考慮是否加try...catch...或者使用exceptionally方法。

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

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

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

3. 默認線程池的注意點

CompletableFuture代碼中又使用了默認的線程池,處理的線程個數是電腦CPU核數-1。在大量請求過來的時候,處理邏輯復雜的話,響應會很慢。一般建議使用自定義線程池,優化線程池配置參數。

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

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

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

參考資料

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

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

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

[4]編程老司機帶你玩轉 CompletableFuture 異步編程: https://zhuanlan.zhihu.com/p/111841508

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

本文轉載自微信公眾號「撿田螺的小男孩」,可以通過以下二維碼關注。轉載本文請聯系撿田螺的小男孩公眾號。

 

責任編輯:武曉燕 來源: 撿田螺的小男孩
相關推薦

2024-04-18 08:20:27

Java 8編程工具

2022-07-08 14:14:04

并發編程異步編程

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異步編程

2017-12-21 15:48:11

JavaCompletable

2025-02-06 16:51:30

2025-02-28 09:20:00

Future開發代碼

2024-12-26 12:59:39

2023-07-19 08:03:05

Future異步JDK

2024-10-14 08:29:14

異步編程任務

2023-11-06 08:14:51

Go語言Context

2024-04-30 11:11:33

aiohttp模塊編程

2024-08-06 09:43:54

Java 8工具編程

2015-06-16 11:06:42

JavaCompletable

2013-04-01 15:38:54

異步編程異步編程模型

2023-11-24 16:13:05

C++編程

2025-04-30 01:50:00

C#異步編程

2013-04-01 15:25:41

異步編程異步EMP
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品一区av | 国产精品99久久久久久www | 精品久久久久久久久久久 | 午夜视频一区二区三区 | 久一久 | 九九国产在线观看 | 成人99| 国产第1页 | 97色在线观看免费视频 | 中文字幕日韩欧美 | 综合精品久久久 | 91精产国品一二三区 | 国产精品一区久久久 | 天天干天天爽 | 日韩一区不卡 | 日韩精品视频在线播放 | 毛片a| 视频三区 | 欧美一级黄色网 | 欧洲精品久久久久毛片完整版 | 亚洲欧美日韩精品久久亚洲区 | 黄色大片在线 | 日韩理论电影在线观看 | 午夜免费视频 | 欧美精品一 | 国产精品久久久久久久久久免费 | 欧美日韩久久 | 久久国产精品视频 | 精品国产乱码久久久久久老虎 | 欧美激情在线观看一区二区三区 | 激情六月丁香 | 久久精品一区二区三区四区 | 久久乐国产精品 | 国产精品永久 | 波多野结衣电影一区 | 精品国产视频在线观看 | 亚洲一区二区在线视频 | 色婷婷久久久亚洲一区二区三区 | 免费精品视频在线观看 | 国产91在线 | 亚洲 | 精品国产一区久久 |