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

什么,你還不會用CompletableFuture?

開發 后端
本篇會介紹CompletableFuture的api,并用一些示例演示如何去使用。

[[387949]]

上一篇我們講了Future機制,有興趣的可以參考談談Future、Callable、FutureTask關系

但Future機制,還不那么靈活,比如怎么去利用Future機制描述兩個任務串行執行,又或是兩個任務并行執行,又或是只關心最先執行結束的任務結果。

Future機制在一定程度上都無法快速地滿足以上需求,CompletableFuture便應運而生了。

本片會介紹CompletableFuture的api,并用一些示例演示如何去使用。

1. 創建一個異步任務

  1. public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) 
  2.  
  3.  public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor); 
  4.  
  5.  public static CompletableFuture<Void> runAsync(Runnable runnable); 
  6.  
  7.  public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor); 

supplyAsync與runAsync的區別在于:supplyAsync有返回值,而runAsync沒有返回值

帶Executor參數的構造函數,則使用線程池中的線程執行異步任務(線程池可以參考說說線程池)

不帶Executor參數的構造函數,則使用ForkJoinPool.commonPool()中的線程執行異步任務(Fork/Join框架可以參考談談并行流parallelStream)

1.1 示例:使用supplyAsync創建一個有返回值的異步任務

  1. public class Case1 { 
  2.  
  3.     public static void main(String[] args) throws Exception { 
  4.  
  5.         CompletableFuture<Integer> completableFuture=CompletableFuture.supplyAsync(()->{ 
  6.             try { 
  7.                 Thread.sleep(1000); 
  8.             } catch (InterruptedException e) { 
  9.                 e.printStackTrace(); 
  10.             } 
  11.             return 1; 
  12.         }); 
  13.         //該方法會一直阻塞 
  14.         Integer result = completableFuture.get(); 
  15.         System.out.println(result); 
  16.     } 
  17.  

2. 異步任務的回調

  1. public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action); 
  2.  
  3.   public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action); 
  4.  
  5.   public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, Executor executor); 
  6.  
  7.   public CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn); 

whenComplete開頭的方法在計算任務完成(包括正常完成與出現異常)之后會回調

而exceptionally則只會在計算任務出現異常時才會被回調

如何確定哪個線程去回調whenComplete,比較復雜,先略過。

而回調whenCompleteAsync的線程比較簡單,隨便拿一個空閑的線程即可,后綴是Async的方法同理。

2.1 示例:計算出現異常,使用whenComplete與exceptionally進行處理

  1. package com.qcy.testCompleteableFuture; 
  2.  
  3. import java.util.concurrent.CompletableFuture; 
  4. import java.util.concurrent.ExecutionException; 
  5. import java.util.function.BiConsumer; 
  6. import java.util.function.Function
  7. import java.util.stream.IntStream; 
  8.  
  9. /** 
  10.  * @author qcy 
  11.  * @create 2020/09/07 17:40:44 
  12.  */ 
  13. public class Case2 { 
  14.  
  15.     public static void main(String[] args) throws Exception { 
  16.  
  17.         CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> { 
  18.             try { 
  19.                 Thread.sleep(1000); 
  20.             } catch (InterruptedException e) { 
  21.                 e.printStackTrace(); 
  22.             } 
  23.             System.out.println("執行supplyAsync的線程:" + Thread.currentThread().getName()); 
  24.             int i = 1 / 0; 
  25.             return 1; 
  26.         }); 
  27.  
  28.         completableFuture.whenComplete(new BiConsumer<Integer, Throwable>() { 
  29.             @Override 
  30.             public void accept(Integer integer, Throwable throwable) { 
  31.                 System.out.println("執行whenComplete的線程:" + Thread.currentThread().getName()); 
  32.                 if (throwable == null) { 
  33.                     System.out.println("計算未出現異常,結果:" + integer); 
  34.                 } 
  35.             } 
  36.         }); 
  37.  
  38.         completableFuture.exceptionally(new Function<Throwable, Integer>() { 
  39.             @Override 
  40.             public Integer apply(Throwable throwable) { 
  41.                 //出現異常時,則返回一個默認值 
  42.                 System.out.println("計算出現異常,信息:" + throwable.getMessage()); 
  43.                 return -1; 
  44.             } 
  45.         }); 
  46.  
  47.         System.out.println(completableFuture.get()); 
  48.     } 
  49.  

輸出:

當然,CompletableFuture內的各種方法是支持鏈式調用與Lambda表達式的,我們進行如下改寫:

  1. public static void main(String[] args) throws Exception { 
  2.  
  3.      CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> { 
  4.          try { 
  5.              Thread.sleep(2000); 
  6.          } catch (InterruptedException e) { 
  7.              e.printStackTrace(); 
  8.          } 
  9.          System.out.println("執行supplyAsync的線程:" + Thread.currentThread().getName()); 
  10.          int i = 1 / 0; 
  11.          return 1; 
  12.      }).whenComplete((integer, throwable) -> { 
  13.          System.out.println("執行whenComplete的線程:" + Thread.currentThread().getName()); 
  14.          if (throwable == null) { 
  15.              System.out.println("計算未出現異常,結果:" + integer); 
  16.          } 
  17.      }).exceptionally(throwable -> { 
  18.          //出現異常時,則返回一個默認值 
  19.          System.out.println("計算出現異常,信息:" + throwable.getMessage()); 
  20.          return -1; 
  21.      }); 
  22.  
  23.      System.out.println("計算結果:" + completableFuture.get()); 
  24.  } 

3. 任務串行化執行

  1. public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn); 
  2.  
  3.   public CompletableFuture<Void> thenRun(Runnable action); 
  4.  
  5.   public CompletableFuture<Void> thenAccept(Consumer<? super T> action); 
  6.  
  7.   public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn); 
  8.  
  9.   public <U> CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn); 

thenApply,依賴上一次任務執行的結果,參數中的Function<? super T,? extends U>,T代表上一次任務返回值的類型,U代表當前任務返回值的類型,當上一個任務沒有出現異常時,thenApply才會被調用

thenRun,不需要知道上一個任務的返回結果,只是在上一個任務執行完成之后開始執行Runnable

thenAccept,依賴上一次任務的執行結果,因為入參是Consumer,所以不返回任何值。

handle和thenApply相似,不過當上一個任務出現異常時,能夠執行handle,卻不會去執行thenApply

thenCompose,傳入一次任務執行的結果,返回一個新的CompleteableFuture對象

3.1 示例:使用串行化任務分解兩數相乘并輸出

  1. package com.qcy.testCompleteableFuture; 
  2.  
  3. import java.util.concurrent.CompletableFuture; 
  4.  
  5. /** 
  6.  * @author qcy 
  7.  * @create 2020/09/07 17:40:44 
  8.  */ 
  9. public class Case4 { 
  10.  
  11.     public static void main(String[] args) { 
  12.          
  13.         CompletableFuture.supplyAsync(() -> 2) 
  14.                 .thenApply(num -> num * 3) 
  15.                 .thenAccept(System.out::print); 
  16.     } 
  17.  

很顯然,輸出為6

3.2 示例:使用串行化任務并且模擬出現異常

  1. package com.qcy.testCompleteableFuture; 
  2.  
  3. import java.util.concurrent.CompletableFuture; 
  4. import java.util.function.BiFunction; 
  5.  
  6. /** 
  7.  * @author qcy 
  8.  * @create 2020/09/07 17:40:44 
  9.  */ 
  10. public class Case4 { 
  11.  
  12.     public static void main(String[] args) { 
  13.  
  14.         CompletableFuture.supplyAsync(() -> 2) 
  15.                 .thenApply(num -> num / 0) 
  16.                 .thenApply(result -> result * 3) 
  17.                 .handle((integer, throwable) -> { 
  18.                     if (throwable == null) { 
  19.                         return integer
  20.                     } else { 
  21.                         throwable.printStackTrace(); 
  22.                         return -1; 
  23.                     } 
  24.                 }).thenAccept(System.out::print); 
  25.     } 
  26.  

最終會輸出-1

4. 任務同時執行,且都需要執行完成

  1. public <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other, 
  2. Function<? super T,? super U,? extends V> fn); 
  3.  
  4.   public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other, 
  5. Consumer<? super T, ? super U> action); 
  6.  
  7.   public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,Runnable action); 
  8.  
  9.   public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs); 

thenCombine,合并兩個任務,兩個任務可以同時執行,都執行成功后,執行最后的BiFunction操作。其中T代表第一個任務的執行結果類型,U代表第二個任務的執行結果類型,V代表合并的結果類型

thenAcceptBoth,和thenCombine特性用法都極其相似,唯一的區別在于thenAcceptBoth進行一個消費,沒有返回值

runAfterBoth,兩個任務都執行完成后,但不關心他們的返回結構,然后去執行一個Runnable。

allOf,當所有的任務都執行完成后,返回一個CompletableFuture

4.1 示例:使用thenCombine合并任務

  1. package com.qcy.testCompleteableFuture; 
  2.  
  3. import java.util.concurrent.CompletableFuture; 
  4. import java.util.concurrent.ExecutionException; 
  5.  
  6. /** 
  7.  * @author qcy 
  8.  * @create 2020/09/07 17:40:44 
  9.  */ 
  10. public class Case5 { 
  11.  
  12.     public static void main(String[] args) throws Exception { 
  13.  
  14.         CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> { 
  15.             System.out.println("任務1開始"); 
  16.             try { 
  17.                 Thread.sleep(3000); 
  18.             } catch (InterruptedException e) { 
  19.                 e.printStackTrace(); 
  20.             } 
  21.             System.out.println("任務1結束"); 
  22.             return 2; 
  23.         }); 
  24.  
  25.         CompletableFuture<Integer> cf2 = CompletableFuture.supplyAsync(() -> { 
  26.             System.out.println("任務2開始"); 
  27.             try { 
  28.                 Thread.sleep(3000); 
  29.             } catch (InterruptedException e) { 
  30.                 e.printStackTrace(); 
  31.             } 
  32.             System.out.println("任務2結束"); 
  33.             return 3; 
  34.         }); 
  35.  
  36.         CompletableFuture<Integer> completableFuture = cf1.thenCombine(cf2, (result1, result2) -> result1 * result2); 
  37.         System.out.println("計算結果:" + completableFuture.get()); 
  38.     } 
  39.  

輸出:

可以看到兩個任務確實是同時執行的

當然,熟練了之后,直接使用鏈式操作,代碼如下:

  1. package com.qcy.testCompleteableFuture; 
  2.  
  3. import java.util.concurrent.CompletableFuture; 
  4.  
  5. /** 
  6.  * @author qcy 
  7.  * @create 2020/09/07 17:40:44 
  8.  */ 
  9. public class Case6 { 
  10.  
  11.     public static void main(String[] args) throws Exception { 
  12.  
  13.         CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> { 
  14.             System.out.println("任務1開始"); 
  15.             try { 
  16.                 Thread.sleep(3000); 
  17.             } catch (InterruptedException e) { 
  18.                 e.printStackTrace(); 
  19.             } 
  20.             System.out.println("任務1結束"); 
  21.             return 2; 
  22.         }).thenCombine(CompletableFuture.supplyAsync(() -> { 
  23.             System.out.println("任務2開始"); 
  24.             try { 
  25.                 Thread.sleep(2000); 
  26.             } catch (InterruptedException e) { 
  27.                 e.printStackTrace(); 
  28.             } 
  29.             System.out.println("任務2結束"); 
  30.             return 3; 
  31.         }), (result1, result2) -> result1 * result2); 
  32.  
  33.         System.out.println("計算結果:" + completableFuture.get()); 
  34.     } 
  35.  

5. 任務同時執行,且只取最先完成的那個任務

  1. public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn); 
  2.  
  3.    public CompletableFuture<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action); 
  4.  
  5.    public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,Runnable action); 
  6.  
  7.    public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs); 

applyToEither,最新執行完任務,將其結果執行Function操作,其中T是最先執行完的任務結果類型,U是最后輸出的類型

acceptEither,最新執行完的任務,將其結果執行消費操作

runAfterEither,任意一個任務執行完成之后,執行Runnable操作

anyOf,多個任務中,返回最先執行完成的CompletableFuture

5.1 示例:兩個任務同時執行,打印最先完成的任務的結果

  1. package com.qcy.testCompleteableFuture; 
  2.  
  3. import java.util.concurrent.CompletableFuture; 
  4.  
  5. /** 
  6.  * @author qcy 
  7.  * @create 2020/09/07 17:40:44 
  8.  */ 
  9. public class Case7 { 
  10.  
  11.     public static void main(String[] args) throws Exception { 
  12.  
  13.         CompletableFuture<Void> completableFuture = CompletableFuture.supplyAsync(() -> { 
  14.             System.out.println("任務1開始"); 
  15.             try { 
  16.                 Thread.sleep(3000); 
  17.             } catch (InterruptedException e) { 
  18.                 e.printStackTrace(); 
  19.             } 
  20.             System.out.println("任務1結束"); 
  21.             return 2; 
  22.         }).acceptEither(CompletableFuture.supplyAsync(() -> { 
  23.             System.out.println("任務2開始"); 
  24.             try { 
  25.                 Thread.sleep(2000); 
  26.             } catch (InterruptedException e) { 
  27.                 e.printStackTrace(); 
  28.             } 
  29.             System.out.println("任務2結束"); 
  30.             return 3; 
  31.         }), result -> System.out.println(result)); 
  32.  
  33.         //等待CompletableFuture返回,防止主線程退出 
  34.         completableFuture.join(); 
  35.     } 
  36.  

輸出:

可以看得到,任務2結束后,直接不再執行任務1的剩余代碼

5.2 示例:多個任務同時執行,打印最先完成的任務的結果

  1. package com.qcy.testCompleteableFuture; 
  2.  
  3. import java.util.concurrent.CompletableFuture; 
  4.  
  5. /** 
  6.  * @author qcy 
  7.  * @create 2020/09/07 17:40:44 
  8.  */ 
  9. public class Case8 { 
  10.  
  11.     public static void main(String[] args) throws Exception { 
  12.  
  13.         CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> { 
  14.             System.out.println("任務1開始"); 
  15.             try { 
  16.                 Thread.sleep(3000); 
  17.             } catch (InterruptedException e) { 
  18.                 e.printStackTrace(); 
  19.             } 
  20.             System.out.println("任務1結束"); 
  21.             return 2; 
  22.         }); 
  23.  
  24.         CompletableFuture<Integer> cf2 = CompletableFuture.supplyAsync(() -> { 
  25.             System.out.println("任務2開始"); 
  26.             try { 
  27.                 Thread.sleep(2000); 
  28.             } catch (InterruptedException e) { 
  29.                 e.printStackTrace(); 
  30.             } 
  31.             System.out.println("任務2結束"); 
  32.             return 3; 
  33.         }); 
  34.  
  35.         CompletableFuture<Integer> cf3 = CompletableFuture.supplyAsync(() -> { 
  36.             System.out.println("任務3開始"); 
  37.             try { 
  38.                 Thread.sleep(4000); 
  39.             } catch (InterruptedException e) { 
  40.                 e.printStackTrace(); 
  41.             } 
  42.             System.out.println("任務3結束"); 
  43.             return 4; 
  44.         }); 
  45.  
  46.         CompletableFuture<Object> firstCf = CompletableFuture.anyOf(cf1, cf2, cf3); 
  47.         System.out.println(firstCf.get()); 
  48.     } 
  49.  

輸出:

 

責任編輯:姜華 來源: 今日頭條
相關推薦

2020-05-14 08:59:28

API網關性能

2022-02-22 08:25:51

typeScript泛型概念泛型使用

2024-09-09 08:36:36

Java操作遠程服務器

2024-08-12 12:25:25

SpringMVC開發

2020-09-01 14:17:03

WindowsDefender微軟

2020-10-21 10:02:16

架構運維技術

2022-08-01 08:17:46

mysqlwindows系統

2020-09-27 06:50:56

Java互聯網注解

2019-09-03 09:30:46

ss 命令SocketLinux

2020-09-15 09:50:47

程序員技能開發者

2020-12-18 09:45:33

DockerLinux命令

2020-08-26 14:40:38

explainMySQL數據庫

2020-11-09 09:03:35

高并發多線程ThreadLocal

2012-05-02 15:38:49

金山快盤網盤

2022-08-12 15:58:34

Docker

2019-11-28 16:48:00

華為Mate X

2018-09-13 10:40:40

Linux命令find

2020-12-07 09:15:00

JavaScript數組 reduce

2022-09-09 14:56:18

Linuxcpu

2021-01-28 09:40:33

運維監控工具軟件
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产乱码精品一区二三赶尸艳谈 | 欧美极品视频在线观看 | 中文字幕免费在线观看 | 日本午夜免费福利视频 | 日韩欧美在线观看 | 成人一区精品 | a在线视频 | 国产亚洲欧美另类一区二区三区 | 国产日韩欧美 | 日韩看片 | 亚洲人成人一区二区在线观看 | 日本三级电影在线观看视频 | 国产色在线 | 午夜欧美 | 2021天天躁夜夜看 | 久久免费视频在线 | 欧美日韩国产在线观看 | 欧美一级电影免费观看 | 欧美国产日韩成人 | 精品国产一区二区 | 观看av| 日韩精品在线播放 | 91网站在线观看视频 | 成人国产网站 | 欧产日产国产精品v | 亚洲先锋影音 | 免费看黄色片 | 国产精品久久久久无码av | 欧美偷偷| 福利一区二区在线 | 精品国产一区二区三区av片 | 国产小视频在线 | 欧美一区二区在线观看 | 欧美理论在线观看 | 久久这里有精品 | 国产美女永久免费无遮挡 | 国产一区三区视频 | 在线观看涩涩视频 | 91伦理片| 久草在线| 欧美日韩一区二区三区在线观看 |