Springboot中@Async異步,實(shí)現(xiàn)異步結(jié)果合并統(tǒng)一返回方式
@Async異步,實(shí)現(xiàn)異步結(jié)果合并統(tǒng)一返回
本文是為了實(shí)現(xiàn)在SpringBoot中使用@Async異步時(shí),將所有異步返回的結(jié)果合并。
舉例
如果我們想拉取三個(gè)數(shù)據(jù),每個(gè)數(shù)據(jù)拉取時(shí)間是2秒鐘,想將結(jié)果統(tǒng)一返回給前端,以往我們都是這么做
@Override
public SysUser getUserA() throws InterruptedException {
System.out.println("A線程:"+Thread.currentThread().getId());
SysUser sysUser = new SysUser();
sysUser.setUserName("A用戶");
Thread.sleep(2000L);
System.out.println("A 拉取成功");
return sysUser;
}
@Override
public SysUser getUserB() throws InterruptedException {
System.out.println("B線程:"+Thread.currentThread().getId());
SysUser sysUser = new SysUser();
sysUser.setUserName("B用戶");
Thread.sleep(2000L);
System.out.println("B 拉取成功");
return sysUser;
}
@Override
public SysUser getUserC() throws InterruptedException {
System.out.println("C線程:"+Thread.currentThread().getId());
SysUser sysUser = new SysUser();
sysUser.setUserName("C用戶");
Thread.sleep(2000L);
System.out.println("C 拉取成功");
return sysUser;
}執(zhí)行拉取測試
@Test
public void testAsync() throws Exception{
System.out.println(new Date());
SysUser a = sysUserService.getUserA();
SysUser b = sysUserService.getUserB();
SysUser c = sysUserService.getUserC();
List<SysUser> list = new ArrayList<>(Arrays.asList(a,b,c));
list.forEach(user->{
System.out.println(user.getUserName());
});
System.out.println(new Date());
}結(jié)果:共耗時(shí)6秒(一個(gè)結(jié)果2秒)

如果我們有個(gè)需求 ,這三個(gè)數(shù)據(jù)一起返回給前端不能超過5秒,這種情形我們就會(huì)使用到異步,
問題
但是如果使用異步,主線程不會(huì)等待異步線程返回,會(huì)直接執(zhí)行之后代碼返回前端(如下圖),前端接收到的就是null

解決
如果我們想達(dá)到異步的結(jié)果統(tǒng)一返回,就需要使用到CompletableFuture
注:使用@Async時(shí),需要@EnableAsync開啟異步,調(diào)用@Async的方法不能與@Async所在同一個(gè)類中

執(zhí)行測試:等待異步返回,并收集結(jié)果,使用.get獲取返回值

結(jié)果:可以看出每個(gè)方法都是異步并行,2秒就即可返回三個(gè)合并后的結(jié)果

當(dāng)前執(zhí)行流程

為什么耗時(shí)是2秒:
CompletableFuture.allOf(a,b,c).join();
我們這里 allOf 傳遞了 三個(gè) 異步線程的返回值, 所以看到上圖,也就出現(xiàn)了三個(gè)等待返回值的坑位 A B C。
可以把這個(gè)想象成一輛車,三個(gè)位, 必須人滿才發(fā)車。
那么要等多久呢?
這三個(gè)人幾乎是同時(shí)走向這輛車的,但是無論其他人走多快,因?yàn)榈谜R齊,所以耗時(shí)取決于這三個(gè)坑位,最慢上車的那個(gè)人。
如果我把其中一個(gè)B線程改為10秒

結(jié)果:可以看出B線程拉取的最慢,并且總耗時(shí)為10秒

注意:
其實(shí),只要你使用到了 返回接收值CompletableFuture ,其實(shí)就已經(jīng)開始觸發(fā),并不是一定要用allOf。
例如:如果我們在使用CompletableFuture時(shí),在異步中途使用到返回值,那么主線程會(huì)等待這個(gè)異步線程返回

結(jié)果:可以看出主線程一直在等待B線程的返回結(jié)果,等待10秒后才繼續(xù)直接線程C

心得:只要調(diào)用了get(),主線程就會(huì)等待異步線程結(jié)果的返回
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot實(shí)現(xiàn)PPT格式文件上傳并在線預(yù)覽功能
本文介紹SpringBoot實(shí)現(xiàn)PPT格式文件上傳并在線預(yù)覽功能,通過上傳接口,可在C盤的tempfile目錄下找到上傳的文件,預(yù)覽時(shí)會(huì)在同級目錄下創(chuàng)建一個(gè)相同文件名后綴為pdf的文件,每次預(yù)覽會(huì)先查找文件是否存在,存在則直接預(yù)覽,不存在則會(huì)走上面的處理,需要的朋友可以參考下2022-02-02
Spring?MVC各種參數(shù)進(jìn)行封裝的方法實(shí)例
這篇文章主要給大家介紹了關(guān)于Spring?MVC各種參數(shù)進(jìn)行封裝的相關(guān)資料,SpringMVC內(nèi)置多種數(shù)據(jù)類型轉(zhuǎn)換器,可以根據(jù)請求中的參數(shù)與后端控制器方法的參數(shù)的關(guān)系為我們實(shí)現(xiàn)簡單的數(shù)據(jù)封裝,需要的朋友可以參考下2023-06-06
Java利用Redis實(shí)現(xiàn)高并發(fā)計(jì)數(shù)器的示例代碼
這篇文章主要介紹了Java利用Redis實(shí)現(xiàn)高并發(fā)計(jì)數(shù)器的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
Mybatis中的游標(biāo)查詢Cursor(滾動(dòng)查詢)
這篇文章主要介紹了Mybatis中的游標(biāo)查詢Cursor(滾動(dòng)查詢),具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
解決maven?maven.compiler.source和maven.compiler.target的坑
這篇文章主要介紹了解決maven?maven.compiler.source和maven.compiler.target的坑,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12

