色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

CompletableFuture異步多線(xiàn)程是真的優(yōu)雅

jf_ro2CN3Fa ? 來(lái)源:芋道源碼 ? 2023-08-07 15:40 ? 次閱讀

949e3ee8-34c2-11ee-9e74-dac502259ad0.gif

這是一個(gè)或許對(duì)你有用的開(kāi)源項(xiàng)目

國(guó)產(chǎn) Star 破 10w+ 的開(kāi)源項(xiàng)目,前端包括管理后臺(tái) + 微信小程序,后端支持單體和微服務(wù)架構(gòu)。

功能涵蓋 RBAC 權(quán)限、SaaS 多租戶(hù)、數(shù)據(jù)權(quán)限、商城、支付、工作流、大屏報(bào)表、微信公眾號(hào)等等功能:

  • Boot 地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro
  • Cloud 地址:https://gitee.com/zhijiantianya/yudao-cloud
  • 視頻教程:https://doc.iocoder.cn

來(lái)源:后端元宇宙

  • 一個(gè)示例回顧Future
  • 通過(guò)CompletableFuture實(shí)現(xiàn)上面示例
  • CompletableFuture創(chuàng)建方式
  • 異步回調(diào)方法
  • 異常回調(diào)
  • 多任務(wù)組合回調(diào)
  • CompletableFuture使用有哪些注意點(diǎn)

952243f0-34c2-11ee-9e74-dac502259ad0.jpg


95379426-34c2-11ee-9e74-dac502259ad0.jpg

一個(gè)示例回顧Future

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

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

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

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

@Test
publicvoidtestFuture()throwsExecutionException,InterruptedException{
ExecutorServiceexecutorService=Executors.newFixedThreadPool(5);
Futurefuture=executorService.submit(()->{
Thread.sleep(2000);
return"hello";
});
System.out.println(future.get());
System.out.println("end");
}

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

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

@Test
publicvoidtestCountDownLatch()throwsInterruptedException,ExecutionException{
ExecutorServiceexecutorService=Executors.newFixedThreadPool(5);
CountDownLatchdownLatch=newCountDownLatch(2);
longstartTime=System.currentTimeMillis();
FutureuserFuture=executorService.submit(()->{
//模擬查詢(xún)商品耗時(shí)500毫秒
Thread.sleep(500);
downLatch.countDown();
return"用戶(hù)A";
});

FuturegoodsFuture=executorService.submit(()->{
//模擬查詢(xún)商品耗時(shí)500毫秒
Thread.sleep(400);
downLatch.countDown();
return"商品A";
});

downLatch.await();
//模擬主程序耗時(shí)時(shí)間
Thread.sleep(600);
System.out.println("獲取用戶(hù)信息:"+userFuture.get());
System.out.println("獲取商品信息:"+goodsFuture.get());
System.out.println("總共用時(shí)"+(System.currentTimeMillis()-startTime)+"ms");

}

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

獲取用戶(hù)信息:用戶(hù)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)雅的解決方式,接下來(lái)來(lái)了解下CompletableFuture的使用。

基于 Spring Boot + MyBatis Plus + Vue & Element 實(shí)現(xiàn)的后臺(tái)管理系統(tǒng) + 用戶(hù)小程序,支持 RBAC 動(dòng)態(tài)權(quán)限、多租戶(hù)、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能

  • 項(xiàng)目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 視頻教程:https://doc.iocoder.cn/video/

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

@Test
publicvoidtestCompletableInfo()throwsInterruptedException,ExecutionException{
longstartTime=System.currentTimeMillis();

//調(diào)用用戶(hù)服務(wù)獲取用戶(hù)基本信息
CompletableFutureuserFuture=CompletableFuture.supplyAsync(()->
//模擬查詢(xún)商品耗時(shí)500毫秒
{
try{
Thread.sleep(500);
}catch(InterruptedExceptione){
e.printStackTrace();
}
return"用戶(hù)A";
});

//調(diào)用商品服務(wù)獲取商品基本信息
CompletableFuturegoodsFuture=CompletableFuture.supplyAsync(()->
//模擬查詢(xún)商品耗時(shí)500毫秒
{
try{
Thread.sleep(400);
}catch(InterruptedExceptione){
e.printStackTrace();
}
return"商品A";
});

System.out.println("獲取用戶(hù)信息:"+userFuture.get());
System.out.println("獲取商品信息:"+goodsFuture.get());

//模擬主程序耗時(shí)時(shí)間
Thread.sleep(600);
System.out.println("總共用時(shí)"+(System.currentTimeMillis()-startTime)+"ms");
}

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

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

通過(guò)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的入參數(shù)等等強(qiáng)大功能,下面就來(lái)學(xué)學(xué)CompletableFuture的API

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實(shí)現(xiàn)的后臺(tái)管理系統(tǒng) + 用戶(hù)小程序,支持 RBAC 動(dòng)態(tài)權(quán)限、多租戶(hù)、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能

  • 項(xiàng)目地址:https://github.com/YunaiV/yudao-cloud
  • 視頻教程:https://doc.iocoder.cn/video/

CompletableFuture創(chuàng)建方式

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

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

publicstaticCompletableFuturesupplyAsync(Suppliersupplier){..}
publicstaticCompletableFuturesupplyAsync(Suppliersupplier,Executorexecutor){..}
publicstaticCompletableFuturerunAsync(Runnablerunnable){..}
publicstaticCompletableFuturerunAsync(Runnablerunnable,Executorexecutor){..}

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

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

「supplyAsync方法」

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

「runAsync方法」

//使用默認(rèn)內(nèi)置線(xiàn)程池ForkJoinPool.commonPool(),根據(jù)runnable構(gòu)建執(zhí)行任務(wù)
publicstaticCompletableFuturerunAsync(Runnablerunnable)
//自定義線(xiàn)程,根據(jù)runnable構(gòu)建執(zhí)行任務(wù)
publicstaticCompletableFuturerunAsync(Runnablerunnable,Executorexecutor)

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

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

//方式一
publicTget()
//方式二
publicTget(longtimeout,TimeUnitunit)
//方式三
publicTgetNow(TvalueIfAbsent)
//方式四
publicTjoin()

說(shuō)明:

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

示例:

@Test
publicvoidtestCompletableGet()throwsInterruptedException,ExecutionException{

CompletableFuturecp1=CompletableFuture.supplyAsync(()->{
try{
Thread.sleep(1000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
return"商品A";
});

//getNow方法測(cè)試
System.out.println(cp1.getNow("商品B"));

//join方法測(cè)試
CompletableFuturecp2=CompletableFuture.supplyAsync((()->1/0));
System.out.println(cp2.join());
System.out.println("-----------------------------------------------------");
//get方法測(cè)試
CompletableFuturecp3=CompletableFuture.supplyAsync((()->1/0));
System.out.println(cp3.get());
}

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

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

異步回調(diào)方法

95657210-34c2-11ee-9e74-dac502259ad0.jpg

1、thenRun/thenRunAsync

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

示例

@Test
publicvoidtestCompletableThenRunAsync()throwsInterruptedException,ExecutionException{
longstartTime=System.currentTimeMillis();

CompletableFuturecp1=CompletableFuture.runAsync(()->{
try{
//執(zhí)行任務(wù)A
Thread.sleep(600);
}catch(InterruptedExceptione){
e.printStackTrace();
}

});

CompletableFuturecp2=cp1.thenRun(()->{
try{
//執(zhí)行任務(wù)B
Thread.sleep(400);
}catch(InterruptedExceptione){
e.printStackTrace();
}
});

//get方法測(cè)試
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è)自定義線(xiàn)程池:

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

說(shuō)明: 后面介紹的thenAcceptthenAcceptAsyncthenApplythenApplyAsync等,它們之間的區(qū)別也是這個(gè)。

2、thenAccept/thenAcceptAsync

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

示例
@Test
publicvoidtestCompletableThenAccept()throwsExecutionException,InterruptedException{
longstartTime=System.currentTimeMillis();
CompletableFuturecp1=CompletableFuture.supplyAsync(()->{
return"dev";

});
CompletableFuturecp2=cp1.thenAccept((a)->{
System.out.println("上一個(gè)任務(wù)的返回結(jié)果為:"+a);
});

cp2.get();
}

3、 thenApply/thenApplyAsync

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

示例

@Test
publicvoidtestCompletableThenApply()throwsExecutionException,InterruptedException{
CompletableFuturecp1=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
}

異常回調(diào)

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

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

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

下面來(lái)看看示例

1、只用whenComplete

@Test
publicvoidtestCompletableWhenComplete()throwsExecutionException,InterruptedException{
CompletableFuturefuture=CompletableFuture.supplyAsync(()->{

if(Math.random()0.5){
thrownewRuntimeException("出錯(cuò)了");
}
System.out.println("正常結(jié)束");
return0.11;

}).whenComplete((aDouble,throwable)->{
if(aDouble==null){
System.out.println("whenCompleteaDoubleisnull");
}else{
System.out.println("whenCompleteaDoubleis"+aDouble);
}
if(throwable==null){
System.out.println("whenCompletethrowableisnull");
}else{
System.out.println("whenCompletethrowableis"+throwable.getMessage());
}
});
System.out.println("最終返回的結(jié)果="+future.get());
}

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

正常結(jié)束
whenCompleteaDoubleis0.11
whenCompletethrowableisnull
最終返回的結(jié)果=0.11

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

whenCompleteaDoubleisnull
whenCompletethrowableisjava.lang.RuntimeException:出錯(cuò)了

java.util.concurrent.ExecutionException:java.lang.RuntimeException:出錯(cuò)了
atjava.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
atjava.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)

2、whenComplete + exceptionally示例

@Test
publicvoidtestWhenCompleteExceptionally()throwsExecutionException,InterruptedException{
CompletableFuturefuture=CompletableFuture.supplyAsync(()->{
if(Math.random()0.5){
thrownewRuntimeException("出錯(cuò)了");
}
System.out.println("正常結(jié)束");
return0.11;

}).whenComplete((aDouble,throwable)->{
if(aDouble==null){
System.out.println("whenCompleteaDoubleisnull");
}else{
System.out.println("whenCompleteaDoubleis"+aDouble);
}
if(throwable==null){
System.out.println("whenCompletethrowableisnull");
}else{
System.out.println("whenCompletethrowableis"+throwable.getMessage());
}
}).exceptionally((throwable)->{
System.out.println("exceptionally中異常:"+throwable.getMessage());
return0.0;
});

System.out.println("最終返回的結(jié)果="+future.get());
}

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

whenCompleteaDoubleisnull
whenCompletethrowableisjava.lang.RuntimeException:出錯(cuò)了
exceptionally中異常:java.lang.RuntimeException:出錯(cuò)了
最終返回的結(jié)果=0.0

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

958594a0-34c2-11ee-9e74-dac502259ad0.jpg

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

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

區(qū)別在于:

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

示例

@Test
publicvoidtestCompletableThenCombine()throwsExecutionException,InterruptedException{
//創(chuàng)建線(xiàn)程池
ExecutorServiceexecutorService=Executors.newFixedThreadPool(10);
//開(kāi)啟異步任務(wù)1
CompletableFuturetask=CompletableFuture.supplyAsync(()->{
System.out.println("異步任務(wù)1,當(dāng)前線(xiàn)程是:"+Thread.currentThread().getId());
intresult=1+1;
System.out.println("異步任務(wù)1結(jié)束");
returnresult;
},executorService);

//開(kāi)啟異步任務(wù)2
CompletableFuturetask2=CompletableFuture.supplyAsync(()->{
System.out.println("異步任務(wù)2,當(dāng)前線(xiàn)程是:"+Thread.currentThread().getId());
intresult=1+1;
System.out.println("異步任務(wù)2結(jié)束");
returnresult;
},executorService);

//任務(wù)組合
CompletableFuturetask3=task.thenCombineAsync(task2,(f1,f2)->{
System.out.println("執(zhí)行任務(wù)3,當(dāng)前線(xiàn)程是:"+Thread.currentThread().getId());
System.out.println("任務(wù)1返回值:"+f1);
System.out.println("任務(wù)2返回值:"+f2);
returnf1+f2;
},executorService);

Integerres=task3.get();
System.out.println("最終結(jié)果:"+res);
}

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

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

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

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

區(qū)別在于:

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

示例

@Test
publicvoidtestCompletableEitherAsync(){
//創(chuàng)建線(xiàn)程池
ExecutorServiceexecutorService=Executors.newFixedThreadPool(10);
//開(kāi)啟異步任務(wù)1
CompletableFuturetask=CompletableFuture.supplyAsync(()->{
System.out.println("異步任務(wù)1,當(dāng)前線(xiàn)程是:"+Thread.currentThread().getId());

intresult=1+1;
System.out.println("異步任務(wù)1結(jié)束");
returnresult;
},executorService);

//開(kāi)啟異步任務(wù)2
CompletableFuturetask2=CompletableFuture.supplyAsync(()->{
System.out.println("異步任務(wù)2,當(dāng)前線(xiàn)程是:"+Thread.currentThread().getId());
intresult=1+2;
try{
Thread.sleep(3000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
System.out.println("異步任務(wù)2結(jié)束");
returnresult;
},executorService);

//任務(wù)組合
task.acceptEitherAsync(task2,(res)->{
System.out.println("執(zhí)行任務(wù)3,當(dāng)前線(xiàn)程是:"+Thread.currentThread().getId());
System.out.println("上一個(gè)任務(wù)的結(jié)果為:"+res);
},executorService);
}

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

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

注意

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

ExecutorServiceexecutorService=Executors.newFixedThreadPool(1);

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

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

3、多任務(wù)組合

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

示例

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

@Test
publicvoidtestCompletableAallOf()throwsExecutionException,InterruptedException{
//創(chuàng)建線(xiàn)程池
ExecutorServiceexecutorService=Executors.newFixedThreadPool(10);
//開(kāi)啟異步任務(wù)1
CompletableFuturetask=CompletableFuture.supplyAsync(()->{
System.out.println("異步任務(wù)1,當(dāng)前線(xiàn)程是:"+Thread.currentThread().getId());
intresult=1+1;
System.out.println("異步任務(wù)1結(jié)束");
returnresult;
},executorService);

//開(kāi)啟異步任務(wù)2
CompletableFuturetask2=CompletableFuture.supplyAsync(()->{
System.out.println("異步任務(wù)2,當(dāng)前線(xiàn)程是:"+Thread.currentThread().getId());
intresult=1+2;
try{
Thread.sleep(3000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
System.out.println("異步任務(wù)2結(jié)束");
returnresult;
},executorService);

//開(kāi)啟異步任務(wù)3
CompletableFuturetask3=CompletableFuture.supplyAsync(()->{
System.out.println("異步任務(wù)3,當(dāng)前線(xiàn)程是:"+Thread.currentThread().getId());
intresult=1+3;
try{
Thread.sleep(4000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
System.out.println("異步任務(wù)3結(jié)束");
returnresult;
},executorService);

//任務(wù)組合
CompletableFutureallOf=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
publicvoidtestCompletableAnyOf()throwsExecutionException,InterruptedException{
//創(chuàng)建線(xiàn)程池
ExecutorServiceexecutorService=Executors.newFixedThreadPool(10);
//開(kāi)啟異步任務(wù)1
CompletableFuturetask=CompletableFuture.supplyAsync(()->{
intresult=1+1;
returnresult;
},executorService);

//開(kāi)啟異步任務(wù)2
CompletableFuturetask2=CompletableFuture.supplyAsync(()->{
intresult=1+2;
returnresult;
},executorService);

//開(kāi)啟異步任務(wù)3
CompletableFuturetask3=CompletableFuture.supplyAsync(()->{
intresult=1+3;
returnresult;
},executorService);

//任務(wù)組合
CompletableFutureanyOf=CompletableFuture.anyOf(task,task2,task3);
//只要有一個(gè)有任務(wù)完成
Objecto=anyOf.get();
System.out.println("完成的任務(wù)的結(jié)果:"+o);
}

			

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

95a77c46-34c2-11ee-9e74-dac502259ad0.jpg

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

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

@Test
publicvoidtestWhenCompleteExceptionally(){
CompletableFuturefuture=CompletableFuture.supplyAsync(()->{
if(1==1){
thrownewRuntimeException("出錯(cuò)了");
}
return0.11;
});

//如果不加get()方法這一行,看不到異常信息
//future.get();
}

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

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

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

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

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

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

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

4、自定義線(xiàn)程池時(shí),注意飽和策略

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

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


聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4803

    瀏覽量

    68769
  • 異步
    +關(guān)注

    關(guān)注

    0

    文章

    62

    瀏覽量

    18073
  • 線(xiàn)程
    +關(guān)注

    關(guān)注

    0

    文章

    505

    瀏覽量

    19713

原文標(biāo)題:奇淫巧技,CompletableFuture 異步多線(xiàn)程是真的優(yōu)雅

文章出處:【微信號(hào):芋道源碼,微信公眾號(hào):芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Java多線(xiàn)程的用法

    本文將介紹一下Java多線(xiàn)程的用法。 基礎(chǔ)介紹 什么是多線(xiàn)程 指的是在一個(gè)進(jìn)程中同時(shí)運(yùn)行多個(gè)線(xiàn)程,每個(gè)線(xiàn)程都可以獨(dú)立執(zhí)行不同的任務(wù)或操作。 與單線(xiàn)程
    的頭像 發(fā)表于 09-30 17:07 ?967次閱讀

    想學(xué)labview異步多線(xiàn)程,大型項(xiàng)目規(guī)范,各類(lèi)通訊的找我

    想學(xué)labview異步多線(xiàn)程,大型項(xiàng)目規(guī)范,各類(lèi)通訊的找我,qq***
    發(fā)表于 02-27 21:19

    如何使用多線(xiàn)程異步操作等并發(fā)設(shè)計(jì)方法來(lái)最大化程序的性能

      異步多線(xiàn)程的區(qū)別  一、異步多線(xiàn)程有什么區(qū)別?其實(shí),異步是目的,而多線(xiàn)程是實(shí)現(xiàn)這個(gè)目的的
    發(fā)表于 08-23 16:31

    LabWindows_CVI多線(xiàn)程技術(shù)的應(yīng)用研究

    分析了線(xiàn)程與進(jìn)程的關(guān)系,研究了LabWindows/CVI多線(xiàn)程技術(shù)運(yùn)行機(jī)制及其數(shù)據(jù)保護(hù)機(jī)制,對(duì)利用異步定時(shí)器實(shí)現(xiàn)的多線(xiàn)程軟件與傳統(tǒng)單線(xiàn)程
    發(fā)表于 08-29 14:53 ?68次下載
    LabWindows_CVI<b class='flag-5'>多線(xiàn)程</b>技術(shù)的應(yīng)用研究

    多線(xiàn)程好還是單線(xiàn)程好?單線(xiàn)程多線(xiàn)程的區(qū)別 優(yōu)缺點(diǎn)分析

    摘要:如今單線(xiàn)程多線(xiàn)程已經(jīng)得到普遍運(yùn)用,那么到底多線(xiàn)程好還是單線(xiàn)程好呢?單線(xiàn)程多線(xiàn)程的區(qū)別又
    發(fā)表于 12-08 09:33 ?8.1w次閱讀

    mfc多線(xiàn)程編程實(shí)例及代碼,mfc多線(xiàn)程間通信介紹

    摘要:本文主要以MFC多線(xiàn)程為中心,分別對(duì)MFC多線(xiàn)程的實(shí)例、MFC多線(xiàn)程之間的通信展開(kāi)的一系列研究,下面我們來(lái)看看原文。
    發(fā)表于 12-08 15:23 ?1.8w次閱讀
    mfc<b class='flag-5'>多線(xiàn)程</b>編程實(shí)例及代碼,mfc<b class='flag-5'>多線(xiàn)程</b>間通信介紹

    什么是多線(xiàn)程編程?多線(xiàn)程編程基礎(chǔ)知識(shí)

    摘要:多線(xiàn)程編程是現(xiàn)代軟件技術(shù)中很重要的一個(gè)環(huán)節(jié)。要弄懂多線(xiàn)程,這就要牽涉到多進(jìn)程。本文主要以多線(xiàn)程編程以及多線(xiàn)程編程相關(guān)知識(shí)而做出的一些結(jié)論。
    發(fā)表于 12-08 16:30 ?1.3w次閱讀

    Java多線(xiàn)程永動(dòng)任務(wù) 多線(xiàn)程異步任務(wù)項(xiàng)目解讀

    , 這個(gè)示例的原型是公司自研的多線(xiàn)程異步任務(wù)項(xiàng)目 ,我把里面涉及到多線(xiàn)程的代碼抽離出來(lái),然后進(jìn)行一定的改造。 里面涉及的知識(shí)點(diǎn)非常多,特別適合有 一定工作經(jīng)驗(yàn) 的同學(xué)學(xué)習(xí),或者可以直接拿到項(xiàng)目中使用。 文章結(jié)構(gòu)非常簡(jiǎn)單: 1.
    的頭像 發(fā)表于 10-19 11:46 ?1129次閱讀

    SpringBoot實(shí)現(xiàn)多線(xiàn)程

    SpringBoot實(shí)現(xiàn)多線(xiàn)程
    的頭像 發(fā)表于 01-12 16:59 ?1842次閱讀
    SpringBoot實(shí)現(xiàn)<b class='flag-5'>多線(xiàn)程</b>

    labview AMC多線(xiàn)程

    labview_AMC多線(xiàn)程
    發(fā)表于 08-21 10:31 ?32次下載

    多線(xiàn)程如何保證數(shù)據(jù)的同步

    多線(xiàn)程編程是一種并發(fā)編程的方法,意味著程序中同時(shí)運(yùn)行多個(gè)線(xiàn)程,每個(gè)線(xiàn)程可獨(dú)立執(zhí)行不同的任務(wù),共享同一份數(shù)據(jù)。由于多線(xiàn)程并發(fā)執(zhí)行的特點(diǎn),會(huì)引發(fā)數(shù)據(jù)同步的問(wèn)題,即保證多個(gè)
    的頭像 發(fā)表于 11-17 14:22 ?1266次閱讀

    mfc多線(xiàn)程編程實(shí)例

    (圖形用戶(hù)界面)應(yīng)用程序的開(kāi)發(fā)。在這篇文章中,我們將重點(diǎn)介紹MFC中的多線(xiàn)程編程。 多線(xiàn)程編程在軟件開(kāi)發(fā)中非常重要,它可以實(shí)現(xiàn)程序的并發(fā)執(zhí)行,提高程序的效率和響應(yīng)速度。MFC提供了豐富的多線(xiàn)程支持,可以輕松地實(shí)現(xiàn)
    的頭像 發(fā)表于 12-01 14:29 ?1527次閱讀

    java實(shí)現(xiàn)多線(xiàn)程的幾種方式

    CompletableFuture 一、繼承Thread類(lèi) 繼承Thread類(lèi)是實(shí)現(xiàn)多線(xiàn)程的最基本方式,只需創(chuàng)建一個(gè)類(lèi)并繼承Thread類(lèi),重寫(xiě)run()方法即可。 ``
    的頭像 發(fā)表于 03-14 16:55 ?757次閱讀

    多線(xiàn)程設(shè)計(jì)模式到對(duì) CompletableFuture 的應(yīng)用

    最近在開(kāi)發(fā) 延保服務(wù) 頻道頁(yè)時(shí),為了提高查詢(xún)效率,使用到了多線(xiàn)程技術(shù)。為了對(duì)多線(xiàn)程方案設(shè)計(jì)有更加充分的了解,在業(yè)余時(shí)間讀完了《圖解 Java 多線(xiàn)程設(shè)計(jì)模式》這本書(shū),覺(jué)得收獲良多。本篇文章將介紹其中
    的頭像 發(fā)表于 06-26 14:18 ?376次閱讀
    從<b class='flag-5'>多線(xiàn)程</b>設(shè)計(jì)模式到對(duì) <b class='flag-5'>CompletableFuture</b> 的應(yīng)用

    Java CompletableFuture 異步超時(shí)實(shí)現(xiàn)探索

    用手段便是多線(xiàn)程并行執(zhí)行。這時(shí)候就會(huì)涉及到 CompletableFuture 的使用。 常見(jiàn)使用方式 下面舉例一個(gè)常見(jiàn)場(chǎng)景。
    的頭像 發(fā)表于 07-25 14:06 ?392次閱讀
    主站蜘蛛池模板: 午夜AV亚洲一码二中文字幕青青| 强姧伦久久久久久久久| 色狠狠xx| 18禁国产精品久久久久久麻豆| 国产色精品久久人妻无码| 欧美日韩亚洲一区二区三区在线观看 | 国产WW高清大片免费看| 年轻老师毛茸茸自由性| 伊人网伊人网| 好好的曰com久久| 香蕉久久夜色精品国产小优 | 狠狠狠色丁香婷婷综合久久| 色中色成人论坛| 色久久一个亚洲综合网| 中国女人hd| 极品少妇高潮XXXXX| 嗯啊…嗯np男男双性总受| 亚洲中文字幕永久在线全国| 国产欧美一区二区三区在线看 | 天天躁日日躁狠狠躁午夜剧场| qvod激情图片| 男人团apk| 66美女人体| 老师xxxx69动漫| 又色又爽又黄gif动态视频| 国语精彩对白2021| 亚洲AV久久久久久久无码| 国产精品伦理一二三区伦理| 色偷偷亚洲男人天堂| 超碰公开在线caopon| 欧美一区二区三区男同| CHINA篮球体育飞机2022网站| 男人团apk| 99er久久国产精品在线| 美女打开双腿扒开屁股男生| 最近中文字幕2018MV高清在线| 久久青草费线频观看国产| 依人青青青在线观看| 精品夜夜澡人妻无码AV蜜桃| 亚洲欧美中文字幕5发布| 狠狠爱亚洲五月婷婷av|