1. 程式人生 > 其它 >第二部分:併發工具類24->CompletableFuture,非同步程式設計沒那麼難

第二部分:併發工具類24->CompletableFuture,非同步程式設計沒那麼難

1.非同步程式設計

序列操作並行化,涉及到非同步化

非同步化,是並行方案得以實施的接觸,利用多執行緒優化效能這個核心方案來實施的基礎。

jdk1.8提供了CompletableFuture支援非同步程式設計

2.CompletableFuture 核心優勢

燒水泡茶,3個任務
任務1,洗水壺,燒開水
任務2,洗茶壺,洗茶杯,拿茶葉
任務3,泡茶

任務3需要等待任務1,和任務2都完成才可以執行

有一些沒有見過的方法,
runAsync()
supplyAsync()
thenCombine()

特點:
1.無需手工維護執行緒,沒有手工維護執行緒的工作,給任務分配執行緒不需要我們關注
2.語意清晰,f3 = f1.thenCombine(f2,() -> {})能夠清晰表述“任務3等待任務1和任務2都完成後才開始”
3.程式碼簡練,專注業務邏輯


//任務1:洗水壺->燒開水
CompletableFuture<Void> f1 = 
  CompletableFuture.runAsync(()->{
  System.out.println("T1:洗水壺...");
  sleep(1, TimeUnit.SECONDS);

  System.out.println("T1:燒開水...");
  sleep(15, TimeUnit.SECONDS);
});
//任務2:洗茶壺->洗茶杯->拿茶葉
CompletableFuture<String> f2 = 
  CompletableFuture.supplyAsync(()->{
  System.out.println("T2:洗茶壺...");
  sleep(1, TimeUnit.SECONDS);

  System.out.println("T2:洗茶杯...");
  sleep(2, TimeUnit.SECONDS);

  System.out.println("T2:拿茶葉...");
  sleep(1, TimeUnit.SECONDS);
  return "龍井";
});
//任務3:任務1和任務2完成後執行:泡茶
CompletableFuture<String> f3 = 
  f1.thenCombine(f2, (__, tf)->{
    System.out.println("T1:拿到茶葉:" + tf);
    System.out.println("T1:泡茶...");
    return "上茶:" + tf;
  });
//等待任務3執行結果
System.out.println(f3.join());

void sleep(int t, TimeUnit u) {
  try {
    u.sleep(t);
  }catch(InterruptedException e){}
}
// 一次執行結果:
T1:洗水壺...
T2:洗茶壺...
T1:燒開水...
T2:洗茶杯...
T2:拿茶葉...
T1:拿到茶葉:龍井
T1:泡茶...
上茶:龍井

3.CompletableFuture物件

建立

//使用預設執行緒池
static CompletableFuture<Void> 
  runAsync(Runnable runnable)
static <U> CompletableFuture<U> 
  supplyAsync(Supplier<U> supplier)
//可以指定執行緒池  
static CompletableFuture<Void> 
  runAsync(Runnable runnable, Executor executor)
static <U> CompletableFuture<U> 
  supplyAsync(Supplier<U> supplier, Executor executor)  

runAsync(Runnable runnable)
supplyAsync(Supplier supplier)

區別是什麼?Runnable介面的run方法沒有返回值,Supplier的get方法是有返回值的,其餘額外的是帶執行緒池傳遞
預設不傳的話用的是預設ForkJoinPool執行緒池,執行緒數預設是cpu核數
建議根據不同業務型別建立不同的執行緒池,以免相互干擾

注意事項:
建立完CompletableFuture物件之後,自動非同步執行runnable.run()方法或者supplier.get()方法

這也可以通過future來獲取執行結果和判斷執行緒是否執行結束。

4.CompletableFuture的高階功能

CompletableFuture類實現了CompletionStage介面,有40多個方法

CompletionStage介面

大概說明:
序列關係

並行關係

匯聚關係

異常處理

前面提到的f3 = f1.thenCombine(f2, () -> {})描述的就是匯聚關係,說白了就是AND聚合關係
f3是等f1,f2都執行完,才執行;當然還是or關係,只有其中1個執行完就可以執行

4.1 序列關係

thenApply,thenAccept,thenRun,thenCompose四個介面


CompletionStage<R> thenApply(fn);
CompletionStage<R> thenApplyAsync(fn);
CompletionStage<Void> thenAccept(consumer);
CompletionStage<Void> thenAcceptAsync(consumer);
CompletionStage<Void> thenRun(action);
CompletionStage<Void> thenRunAsync(action);
CompletionStage<R> thenCompose(fn);
CompletionStage<R> thenComposeAsync(fn);

4.2 and 匯聚關係

CompletionStage applyToEither(other, fn);
CompletionStage applyToEitherAsync(other, fn);
CompletionStage acceptEither(other, consumer);
CompletionStage acceptEitherAsync(other, consumer);
CompletionStage runAfterEither(other, action);
CompletionStage runAfterEitherAsync(other, action);

CompletionStage<R> thenCombine(other, fn);
CompletionStage<R> thenCombineAsync(other, fn);
CompletionStage<Void> thenAcceptBoth(other, consumer);
CompletionStage<Void> thenAcceptBothAsync(other, consumer);
CompletionStage<Void> runAfterBoth(other, action);
CompletionStage<Void> runAfterBothAsync(other, action);

4.3 or匯聚關係


CompletionStage applyToEither(other, fn);
CompletionStage applyToEitherAsync(other, fn);
CompletionStage acceptEither(other, consumer);
CompletionStage acceptEitherAsync(other, consumer);
CompletionStage runAfterEither(other, action);
CompletionStage runAfterEitherAsync(other, action);

4.4 異常處理


CompletableFuture<Integer> 
  f0 = CompletableFuture.
    .supplyAsync(()->(7/0))
    .thenApply(r->r*10);
System.out.println(f0.join());

正常是try-catch,函數語言程式設計中,更簡單,提供了鏈式處理異常


CompletionStage exceptionally(fn);
CompletionStage<R> whenComplete(consumer);
CompletionStage<R> whenCompleteAsync(consumer);
CompletionStage<R> handle(fn);
CompletionStage<R> handleAsync(fn);

異常範例

CompletableFuture f0 = CompletableFuture .supplyAsync(()->(7/0)) .thenApply(r->r*10) .exceptionally(e->0);System.out.println(f0.join());
原創:做時間的朋友