Spring Boot集成教程之異步調(diào)用Async
前言
本文主要給大家介紹了關(guān)于Spring Boot集成之異步調(diào)用Async的相關(guān)內(nèi)容,分享出來供大家參考學(xué)習(xí),下面話不多說了,來一起看看詳細(xì)的介紹吧。
什么是異步調(diào)用?
異步調(diào)用是相對于同步調(diào)用而言的,同步調(diào)用是指程序按預(yù)定順序一步步執(zhí)行,每一步必須等到上一步執(zhí)行完后才能執(zhí)行,異步調(diào)用則無需等待上一步程序執(zhí)行完即可執(zhí)行。
異步處理方式
- 調(diào)用之后,不返回任何數(shù)據(jù)。
- 調(diào)用之后,返回數(shù)據(jù),通過Future來獲取返回數(shù)據(jù)
如何實(shí)現(xiàn)異步調(diào)用?
多線程,這是很多人第一眼想到的關(guān)鍵詞,沒錯,多線程就是一種實(shí)現(xiàn)異步調(diào)用的方式。
在非spring目項(xiàng)目中我們要實(shí)現(xiàn)異步調(diào)用的就是使用多線程方式,可以自己實(shí)現(xiàn)Runable接口或者集成Thread類,或者使用jdk1.5以上提供了的Executors線程池。
StrngBoot中則提供了很方便的方式執(zhí)行異步調(diào)用。
按照官方示例開擼
代碼入下
maven依賴:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.3.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
啟動類:添加@EnableAsync注解
@SpringBootApplication
@EnableAsync
public class Application{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Controller
只需在需要異步執(zhí)行方法上添加@Async注解
@RestController
@RequestMapping("")
public class AsyncTaskController {
@RequestMapping("")
public String doTask() throws InterruptedException{
long currentTimeMillis = System.currentTimeMillis();
this.task1();
this.task2();
this.task3();
long currentTimeMillis1 = System.currentTimeMillis();
return "task任務(wù)總耗時:"+(currentTimeMillis1-currentTimeMillis)+"ms";
}
@Async
public void task1() throws InterruptedException{
long currentTimeMillis = System.currentTimeMillis();
Thread.sleep(1000);
long currentTimeMillis1 = System.currentTimeMillis();
System.out.println("task1任務(wù)耗時:"+(currentTimeMillis1-currentTimeMillis)+"ms");
}
@Async
public void task2() throws InterruptedException{
long currentTimeMillis = System.currentTimeMillis();
Thread.sleep(2000);
long currentTimeMillis1 = System.currentTimeMillis();
System.out.println("task2任務(wù)耗時:"+(currentTimeMillis1-currentTimeMillis)+"ms");
}
@Async
public void task3() throws InterruptedException{
long currentTimeMillis = System.currentTimeMillis();
Thread.sleep(3000);
long currentTimeMillis1 = System.currentTimeMillis();
System.out.println("task3任務(wù)耗時:"+(currentTimeMillis1-currentTimeMillis)+"ms");
}
}
main函數(shù)運(yùn)行spirngboot項(xiàng)目,啟動完成后瀏覽器訪問:http://localhost:8080/
控制臺:
task1任務(wù)耗時:1012ms task2任務(wù)耗時:2009ms task3任務(wù)耗時:3004ms
等了一段瀏覽器時候輸出入下:
task任務(wù)總耗時:6002ms
異步并沒有執(zhí)行!
難道是代碼寫錯了?反復(fù)檢查了好幾遍,并沒有發(fā)現(xiàn)什么明顯錯誤,想起spring對@Transactional注解時也有類似問題,spring掃描時具有@Transactional注解方法的類時,是生成一個代理類,由代理類去開啟關(guān)閉事務(wù),而在同一個類中,方法調(diào)用是在類體內(nèi)執(zhí)行的,spring無法截獲這個方法調(diào)用。
豁然開朗,將異步任務(wù)單獨(dú)放到一個類中,調(diào)整代碼入下:
Controller
@RequestMapping("")
@RestController
public class AsyncTaskController {
@Autowired
private AsyncTask asyncTask;
@RequestMapping("")
public String doTask() throws InterruptedException{
long currentTimeMillis = System.currentTimeMillis();
asyncTask.task1();
asyncTask.task2();
asyncTask.task3();
long currentTimeMillis1 = System.currentTimeMillis();
return "task任務(wù)總耗時:"+(currentTimeMillis1-currentTimeMillis)+"ms";
}
}
異步任務(wù)類
@Component
public class AsyncTask {
@Async
public void task1() throws InterruptedException{
long currentTimeMillis = System.currentTimeMillis();
Thread.sleep(1000);
long currentTimeMillis1 = System.currentTimeMillis();
System.out.println("task1任務(wù)耗時:"+(currentTimeMillis1-currentTimeMillis)+"ms");
}
@Async
public void task2() throws InterruptedException{
long currentTimeMillis = System.currentTimeMillis();
Thread.sleep(2000);
long currentTimeMillis1 = System.currentTimeMillis();
System.out.println("task2任務(wù)耗時:"+(currentTimeMillis1-currentTimeMillis)+"ms");
}
@Async
public void task3() throws InterruptedException{
long currentTimeMillis = System.currentTimeMillis();
Thread.sleep(3000);
long currentTimeMillis1 = System.currentTimeMillis();
System.out.println("task3任務(wù)耗時:"+(currentTimeMillis1-currentTimeMillis)+"ms");
}
}
控制臺:
task1任務(wù)耗時:1012ms task2任務(wù)耗時:2009ms task3任務(wù)耗時:3004ms
訪問瀏覽器結(jié)果入下:
task任務(wù)總耗時:19ms
異步調(diào)用成功!
如何知道三個異步任務(wù)什么時候執(zhí)行完,執(zhí)行的結(jié)果怎樣呢?可以采用添加Fature回調(diào)方式判斷
代碼入下:
異步任務(wù)類
@Component
public class AsyncTask {
@Async
public Future<String> task1() throws InterruptedException{
long currentTimeMillis = System.currentTimeMillis();
Thread.sleep(1000);
long currentTimeMillis1 = System.currentTimeMillis();
System.out.println("task1任務(wù)耗時:"+(currentTimeMillis1-currentTimeMillis)+"ms");
return new AsyncResult<String>("task1執(zhí)行完畢");
}
@Async
public Future<String> task2() throws InterruptedException{
long currentTimeMillis = System.currentTimeMillis();
Thread.sleep(2000);
long currentTimeMillis1 = System.currentTimeMillis();
System.out.println("task2任務(wù)耗時:"+(currentTimeMillis1-currentTimeMillis)+"ms");
return new AsyncResult<String>("task2執(zhí)行完畢");
}
@Async
public Future<String> task3() throws InterruptedException{
long currentTimeMillis = System.currentTimeMillis();
Thread.sleep(3000);
long currentTimeMillis1 = System.currentTimeMillis();
System.out.println("task3任務(wù)耗時:"+(currentTimeMillis1-currentTimeMillis)+"ms");
return new AsyncResult<String>("task3執(zhí)行完畢");
}
}
Controller
@RequestMapping("")
@RestController
public class AsyncTaskController {
@Autowired
private AsyncTask asyncTask;
@RequestMapping("")
public String doTask() throws InterruptedException{
long currentTimeMillis = System.currentTimeMillis();
Future<String> task1 = asyncTask.task1();
Future<String> task2 = asyncTask.task2();
Future<String> task3 = asyncTask.task3();
String result = null;
for (;;) {
if(task1.isDone() && task2.isDone() && task3.isDone()) {
// 三個任務(wù)都調(diào)用完成,退出循環(huán)等待
break;
}
Thread.sleep(1000);
}
long currentTimeMillis1 = System.currentTimeMillis();
result = "task任務(wù)總耗時:"+(currentTimeMillis1-currentTimeMillis)+"ms";
return result;
}
}
控制臺輸出:
task1任務(wù)耗時:1000ms task2任務(wù)耗時:2001ms task3任務(wù)耗時:3001ms
瀏覽器輸出:
task任務(wù)總耗時:4015ms
異步調(diào)用成功,并且在所有任務(wù)都完成時程序才返回了結(jié)果!
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
- 詳解SpringBoot中異步請求和異步調(diào)用(看完這一篇就夠了)
- Spring Boot利用@Async異步調(diào)用:使用Future及定義超時詳解
- Spring Boot利用@Async異步調(diào)用:ThreadPoolTaskScheduler線程池的優(yōu)雅關(guān)閉詳解
- Spring Boot利用@Async如何實(shí)現(xiàn)異步調(diào)用:自定義線程池
- 深入理解spring boot異步調(diào)用方式@Async
- spring boot 使用@Async實(shí)現(xiàn)異步調(diào)用方法
- spring boot中使用@Async實(shí)現(xiàn)異步調(diào)用任務(wù)
- SpringBoot異步調(diào)用方法實(shí)現(xiàn)場景代碼實(shí)例
相關(guān)文章
springboot整合mybatis-plus基于注解實(shí)現(xiàn)一對一(一對多)查詢功能
這篇文章主要介紹了springboot整合mybatis-plus基于純注解實(shí)現(xiàn)一對一(一對多)查詢功能,因?yàn)楸救瞬捎玫氖莝pring-boot進(jìn)行開發(fā),本身springboot就提倡采用不用配置自動配置的方式,所以真心希望mybatis(不是mybatis-plus)這點(diǎn)需要繼續(xù)努力2021-09-09
Java?精煉解讀數(shù)據(jù)結(jié)構(gòu)的鏈表的概念與實(shí)現(xiàn)
鏈表是一種物理存儲單元上非連續(xù)、非順序的存儲結(jié)構(gòu),數(shù)據(jù)元素的邏輯順序是通過鏈表中的指針連接次序?qū)崿F(xiàn)的,每一個鏈表都包含多個節(jié)點(diǎn),節(jié)點(diǎn)又包含兩個部分,一個是數(shù)據(jù)域,一個是引用域2022-03-03
java中File與MultipartFile互轉(zhuǎn)代碼示例
在Java開發(fā)中,當(dāng)需要將本地File對象轉(zhuǎn)換為MultipartFile對象以處理文件上傳時,可以通過實(shí)現(xiàn)MultipartFile接口或使用CommonsMultipartFile類來實(shí)現(xiàn),本文提供了詳細(xì)的轉(zhuǎn)換方法和代碼示例,需要的朋友可以參考下2024-10-10
SpringBoot 應(yīng)用程序測試實(shí)現(xiàn)方案
這篇文章主要介紹了SpringBoot 應(yīng)用程序測試實(shí)現(xiàn)方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11
IDEA 非常重要的一些設(shè)置項(xiàng)(一連串的問題差點(diǎn)讓我重新用回 Eclipse)
這篇文章主要介紹了IDEA 非常重要的一些設(shè)置項(xiàng)(一連串的問題差點(diǎn)讓我重新用回 Eclipse),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08
java使用elasticsearch分組進(jìn)行聚合查詢過程解析
這篇文章主要介紹了java使用elasticsearch分組進(jìn)行聚合查詢過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-02-02
詳解使用@RequestBody取POST方式的json字符串
這篇文章主要介紹了詳解使用@RequestBody取POST方式的json字符串,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
Spring Boot + Kotlin整合MyBatis的方法教程
前幾天由于工作需要,便開始學(xué)習(xí)了kotlin,java基礎(chǔ)扎實(shí)學(xué)起來也還算比較快,對于kotlin這個編程語言自然是比java有趣一些,下面這篇文章主要給大家介紹了關(guān)于Spring Boot + Kotlin整合MyBatis的方法教程,需要的朋友可以參考下。2018-01-01

