詳解springboot使用異步注解@Async獲取執(zhí)行結(jié)果的坑
一、引言
在java后端開發(fā)中經(jīng)常會碰到處理多個任務的情況,比如一個方法中要調(diào)用多個請求,然后把多個請求的結(jié)果合并后統(tǒng)一返回,一般情況下調(diào)用其他的請求一般都是同步的,也就是每個請求都是阻塞的,那么這個處理時間必定是很長的,有沒有一種方法可以讓多個請求異步處理那,答案是有的。
springboot中提供了很便利的方式可以解決上面的問題,那就是異步注解@Async。正確的使用該注解可以使你的程序飛起,相反如果使用不當那么并不會取到理想的效果。
二、獲取異步執(zhí)行結(jié)果
1、環(huán)境介紹
下面是我的controller,SyncController.java
package com.atssg.controller;
import com.atssg.service.MySyncService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@RequestMapping("/sync")
public class SyncController {
@Autowired
private MySyncService syncService;
@GetMapping(value = "/test")
public String test() {
String str=null;
try {
log.info("start");
str = syncService.asyncMethod();
log.info("str:{}", str);
return str;
} catch (Exception e) {
e.printStackTrace();
}
return str;
}
}
在controller中就是調(diào)用下層的方法并返回,再看service層的類MySyncService.java
package com.atssg.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@Service
public class MySyncService {
@Autowired
private SyncService syncService;
/**
* 異步方法
*
* @return
* @throws InterruptedException
* @throws ExecutionException
*/
public String asyncMethod() throws InterruptedException, ExecutionException {
Future<String> result1 = syncService.method1("I");
Future<String> result2 = syncService.method2("love");
Future<String> result3 = syncService.method3("async");
String str = result1.get();
String str2 = result2.get();
String str3 = result3.get();
String result = str + str2 + str3;
return result;
}
/**
* 同步方法
*
* @return
* @throws InterruptedException
* @throws ExecutionException
*/
public String syncMethod() throws InterruptedException, ExecutionException {
/*同步寫法*/
String str = syncService.method1("I").get();
String str2 = syncService.method2("love").get();
String str3 = syncService.method3("async").get();
return str + str2 + str3;
}
}
上面便是service類,僅僅是調(diào)用下次異步層的方法,并取得返回值。上面類中有兩個方法,其寫法也類似但結(jié)果卻大不相同,后面詳說。
下面是異步層的方法,SyncService.java
package com.atssg.service;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import java.util.concurrent.Future;
@Service
@Async
public class SyncService {
//@Async
public Future<String> method1(String str) throws InterruptedException {
Thread.sleep(1000*10);
return new AsyncResult<>( str);
}
//@Async
public Future<String> method2(String str) throws InterruptedException {
Thread.sleep(1000*5);
return new AsyncResult<>(str);
}
// @Async
public Future<String> method3(String str) throws InterruptedException {
Thread.sleep(1000*15);
return new AsyncResult<>(str);
}
}
該類使用@Async注解,表明該類中所有的方法都是異步執(zhí)行的,其中@Async可修飾類也可以修飾方法。
這便是所有的環(huán)境。
2、錯誤的方式
在MySyncService中有兩個方法,先看其中一個方法
public String syncMethod() throws InterruptedException, ExecutionException {
/*同步寫法*/
String str = syncService.method1("I").get();
String str2 = syncService.method2("love").get();
String str3 = syncService.method3("async").get();
return str + str2 + str3;
}
這種寫法是調(diào)用異步方法后立即調(diào)用get()方法,即獲取結(jié)果,下面看測試結(jié)果,在controllor中調(diào)用該方法,下面看執(zhí)行結(jié)果
2021-08-21 11:06:28.612 INFO 3584 --- [nio-8080-exec-1] com.atssg.controller.SyncController : start
2021-08-21 11:06:58.651 INFO 3584 --- [nio-8080-exec-1] com.atssg.controller.SyncController : str:Iloveasync
可以看到共執(zhí)行了30s,在異步層的方法中的三個方法如下,
//@Async
public Future<String> method1(String str) throws InterruptedException {
Thread.sleep(1000*10);
return new AsyncResult<>( str);
}
//@Async
public Future<String> method2(String str) throws InterruptedException {
Thread.sleep(1000*5);
return new AsyncResult<>(str);
}
// @Async
public Future<String> method3(String str) throws InterruptedException {
Thread.sleep(1000*15);
return new AsyncResult<>(str);
}
可以看到這三個方法分別是睡眠10s、5s、15s,這就很好理解了syncMethod()方法中的寫法是同步的,未達到異步的目的,切記調(diào)用完異步方法進接著調(diào)用get()方法不是異步的方式,而是同步的。
3、正確方式
上面看了錯誤的用法,下面看正確的方式,
public String asyncMethod() throws InterruptedException, ExecutionException {
Future<String> result1 = syncService.method1("I");
Future<String> result2 = syncService.method2("love");
Future<String> result3 = syncService.method3("async");
String str = result1.get();
String str2 = result2.get();
String str3 = result3.get();
String result = str + str2 + str3;
return result;
}
這種方式是首先調(diào)用異步方法,然后分別調(diào)用get()方法,取得執(zhí)行結(jié)果。下面看測試結(jié)果
2021-08-21 11:17:23.516 INFO 3248 --- [nio-8080-exec-1] com.atssg.controller.SyncController : start
2021-08-21 11:17:38.535 INFO 3248 --- [nio-8080-exec-1] com.atssg.controller.SyncController : str:Iloveasync
執(zhí)行時間未15s,這就很好解釋了,異步層的三個方法,分別睡眠的時間是10s、5s、15s,既然是異步執(zhí)行的,那么總的執(zhí)行時間肯定是三個方法中最長的那個,符合測試結(jié)果。這才@Async正確的打開姿勢。
三、異步執(zhí)行@Async注解
@Async注解的定義如下,
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Async {
String value() default "";
}
可以看到該注解可以用在類及方法上,用在類上表示類中的所有方法都是異步的,用在方法上表示該方法是異步的。
四、總結(jié)
今天的文章分享到這里,主要分享了關于@Async注解在獲取執(zhí)行結(jié)果的時候的坑,一定要先調(diào)用異步方法,然后再調(diào)用get()方法,獲取結(jié)果,其中g(shù)et方法還有一個重載的,可以設置超時時間,即超過設置的超時時間便返回,不再等待,各位小伙伴可以自己試驗。
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
下次繼續(xù)分享有關@Async注解使用的一些小細節(jié),歡迎持續(xù)關注。
到此這篇關于詳解springboot使用異步注解@Async獲取執(zhí)行結(jié)果的坑的文章就介紹到這了,更多相關springboot使用異步注解@Async 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
執(zhí)行java請求時導致在腳本執(zhí)行結(jié)束時JVM無法退出
這篇文章主要介紹了執(zhí)行java請求,導致在腳本執(zhí)行結(jié)束時JVM無法退出問題,本文通過原因分析給出解決方案,需要的朋友可以參考下2020-02-02
Java實現(xiàn)二分查找BinarySearch算法
這篇文章主要介紹了Java實現(xiàn)二分查找BinarySearch算法,二分查找針對的是一個有序的數(shù)據(jù)集合,每次都通過跟區(qū)間的中間元素對比,將待查找的區(qū)間縮小為之前的一半,直到找到要查找的元素,或者區(qū)間被縮小為 0,需要的朋友可以參考下2023-12-12
基于SpringBoot+Redis的Session共享與單點登錄詳解
這篇文章主要介紹了基于SpringBoot+Redis的Session共享與單點登錄,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-07-07
springboot 啟動時初始化數(shù)據(jù)庫的步驟
這篇文章主要介紹了springboot 啟動時初始化數(shù)據(jù)庫的步驟,幫助大家更好的理解和使用springboot框架,感興趣的朋友可以了解下2021-01-01
GsonFormat快速生成JSon實體類的實現(xiàn)
GsonFormat主要用于使用Gson庫將JSONObject格式的String?解析成實體,本文主要介紹了GsonFormat快速生成JSon實體類的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下2023-05-05
Java8實現(xiàn)對List<Integer>的求和
這篇文章主要介紹了Java8實現(xiàn)對List<Integer>的求和方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-05-05

