springboot的異步任務(wù):無返回值和有返回值問題
springboot異步任務(wù):無返回值和有返回值
在想要異步執(zhí)行的方法上加上@Async注解,在controller上加上@EnableAsync,即可。
注:這里的異步方法,只能在本類之外調(diào)用,在本類調(diào)用是無效的。
無返回值的異步任務(wù)
service實(shí)現(xiàn)部分:
@Service public class AsyncService { ? ? @Async //想要異步執(zhí)行的方法上加@Async 注解 ? ? public void doNoReturn(){ ? ? ? ? try { ? ? ? ? ? ? // 這個(gè)方法執(zhí)行需要三秒 ? ? ? ? ? ? Thread.sleep(3000); ? ? ? ? ? ? System.out.println("方法執(zhí)行結(jié)束" + new Date()); ? ? ? ? } catch (InterruptedException e) { ? ? ? ? ? ? e.printStackTrace(); ? ? } }
controller調(diào)用部分:
@RestController @EnableAsync//調(diào)用異步任務(wù)的controller上加@EnableAsync注解 public class AsyncController { ? ? @Autowired ? ? private AsyncService asyncService; ? ? @RequestMapping(value = "/hello",method = RequestMethod.GET) ? ? public String testAsyncNoRetrun(){ ? ? ? ? long start = System.currentTimeMillis(); ? ? ? ? ?asyncService.doNoReturn(); ? ? ? ? ?return String.format("任務(wù)執(zhí)行成功,耗時(shí){%s}", System.currentTimeMillis() - start); ? ? }
輸出:
任務(wù)執(zhí)行成功,耗時(shí){4}
可見testAsyncNoRetrun()方法中 調(diào)用doNoReturn(),沒等doNoReturn()執(zhí)行完即返回。
有返回值的異步任務(wù)
有返回值的異步任務(wù)方法需要用Futrue變量把返回值封裝起來。
service實(shí)現(xiàn)部分:
@Async ?public Future<String> doReturn(int i){ ? ? ? ? try { ? ? ? ? ? ? // 這個(gè)方法需要調(diào)用500毫秒 ? ? ? ? ? ? Thread.sleep(500); ? ? ? ? } catch (InterruptedException e) { ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? } ? ? ? ? // 消息匯總 ? ? ? ? return new AsyncResult<>(String.format("這個(gè)是第{%s}個(gè)異步調(diào)用的證書", i)); }
讀取的時(shí)候要批量讀取不能單獨(dú)讀取。
controller調(diào)用部分:
@GetMapping("/hi") ? ? public Map<String, Object> testAsyncReturn() throws ExecutionException, InterruptedException { ? ? ? ? long start = System.currentTimeMillis(); ? ? ? ? Map<String, Object> map = new HashMap<>(); ? ? ? ? List<Future<String>> futures = new ArrayList<>(); ? ? ? ? for (int i = 0; i < 10; i++) { ? ? ? ? ? ? Future<String> future = asyncService.doReturn(i); ? ? ? ? ? ? futures.add(future); ? ? ? ? } ? ? ? ? List<String> response = new ArrayList<>(); ? ? ? ? for (Future future : futures) { ? ? ? ? ? ? String string = (String) future.get(); ? ? ? ? ? ? response.add(string); ? ? ? ? } ? ? ? ? map.put("data", response); ? ? ? ? map.put("消耗時(shí)間", String.format("任務(wù)執(zhí)行成功,耗時(shí){%s}毫秒", System.currentTimeMillis() - start)); ? ? ? ? return map; }
在瀏覽器輸入地址:http://localhost:8080/hi
結(jié)果如下: 耗時(shí)500多毫秒的意思代表,springboot自帶異步任務(wù)線程池是小于10的大小的
{"data":["這個(gè)是第{0}個(gè)異步調(diào)用的證書","這個(gè)是第{1}個(gè)異步調(diào)用的證書","這個(gè)是第{2}個(gè)異步調(diào)用的證書","這個(gè)是第{3}個(gè)異步調(diào)用的證書","這個(gè)是第{4}個(gè)異步調(diào)用的證書","這個(gè)是第{5}個(gè)異步調(diào)用的證書","這個(gè)是第{6}個(gè)異步調(diào)用的證書","這個(gè)是第{7}個(gè)異步調(diào)用的證書","這個(gè)是第{8}個(gè)異步調(diào)用的證書","這個(gè)是第{9}個(gè)異步調(diào)用的證書"],"消耗時(shí)間":"任務(wù)執(zhí)行成功,耗時(shí){508}毫秒"}
springboot的異步任務(wù)(帶返回值和不帶返回值的處理)
注意:在用異步任務(wù)之前先給啟動(dòng)類加@EnableAsync這個(gè)注解
新建異步任務(wù)包和在包里面建異步任務(wù)類
As.java異步類
package com.example.demo.async; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.AsyncResult; import org.springframework.stereotype.Component; import java.util.concurrent.Future; //注意:1、要把異步任務(wù)寫進(jìn)一個(gè)類里面而不能直接寫在controller中 // 2、如果需要拿到結(jié)果,則需要在調(diào)用處判斷全部的task.isDone()來確定異步任務(wù)的完成 @Component //異步類注解,表明整個(gè)類的方法都是異步方法,如果把這個(gè)注解加在某一個(gè)方法上而不是某一個(gè)類則表明僅僅是這個(gè)方法才是異步方法 @Async public class As { //下面是3個(gè)異步任務(wù)(不帶返回值的) public void task1() throws InterruptedException { long begin=System.currentTimeMillis(); Thread.sleep(3000l); long end=System.currentTimeMillis(); System.out.println("任務(wù)1耗時(shí)"+(end-begin)); } public void task2() throws InterruptedException { long begin=System.currentTimeMillis(); Thread.sleep(2000l); long end=System.currentTimeMillis(); System.out.println("任務(wù)2耗時(shí)"+(end-begin)); } public void task3() throws InterruptedException { long begin=System.currentTimeMillis(); Thread.sleep(1000l); long end=System.currentTimeMillis(); System.out.println("任務(wù)3耗時(shí)"+(end-begin)); } //下面是3個(gè)異步任務(wù)(帶返回值的,可以在調(diào)用出取地返回值) public Future<String> task4() throws InterruptedException { long begin=System.currentTimeMillis(); Thread.sleep(3000l); long end=System.currentTimeMillis(); return new AsyncResult<String>("任務(wù)4耗時(shí)"+(end-begin)); } public Future<String> task5() throws InterruptedException { long begin=System.currentTimeMillis(); Thread.sleep(2000l); long end=System.currentTimeMillis(); return new AsyncResult<String>("任務(wù)5耗時(shí)"+(end-begin)); } public Future<String> task6() throws InterruptedException { long begin=System.currentTimeMillis(); Thread.sleep(1000l); long end=System.currentTimeMillis(); return new AsyncResult<String>("任務(wù)6耗時(shí)"+(end-begin)); } }
controller測(cè)試控制器
package com.example.demo.controller; import com.example.demo.async.As; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @RestController public class He { //注入異步類 @Autowired private As as; //測(cè)試異步任務(wù)沒帶返回值的,直接主線程瞬間就通過了 @RequestMapping("/as") public Object as() throws InterruptedException { long begin=System.currentTimeMillis(); as.task1(); as.task2(); as.task3(); long end=System.currentTimeMillis(); return "總耗時(shí)+"+(end-begin); } //測(cè)試異步任務(wù)帶返回值的,總耗時(shí)是最慢的那個(gè)任務(wù)的耗時(shí) @RequestMapping("/asHava") public Object ash() throws InterruptedException, ExecutionException { long begin=System.currentTimeMillis(); Future<String> task4=as.task4(); Future<String> task5=as.task5(); Future<String> task6=as.task6(); //先小堵塞主線程一會(huì),用以拿到異步任務(wù)返回值 while (!(task4.isDone()&&task5.isDone()&&task6.isDone())){ } long end=System.currentTimeMillis(); //取得異步任務(wù)的返回值并查看總耗時(shí) return "總耗時(shí)+"+(end-begin)+" task4結(jié)果:"+task4.get()+" task5結(jié)果:"+task5.get()+" task6結(jié)果:"+task6.get(); //結(jié)果是3s左右,因?yàn)檫M(jìn)入接口,三個(gè)異步任務(wù)瞬間開啟,再瞬間到while這兒堵起 //由于三個(gè)異步任務(wù)幾乎是同時(shí)開啟的,所以等最慢的那個(gè)異步任務(wù)完成以后,肯定所有的異步任務(wù)都完成了 //所以while這時(shí)才都為true,那么放開while,所以結(jié)果就是最慢的那個(gè)異步任務(wù)的時(shí)間 //如果說不用這種異步取值而用同步的話,那么時(shí)間就是1+2+3就是6s左右,而不是最慢的那個(gè)任務(wù)的時(shí)間 } }
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
從最基本的Java工程搭建SpringMVC+SpringDataJPA+Hibernate
本文會(huì)介紹從一個(gè)最基本的java工程,到Web工程,到集成Spring、SpringMVC、SpringDataJPA+Hibernate,本文介紹的非常詳細(xì),具有參考借鑒價(jià)值,感興趣的朋友一起學(xué)習(xí)吧2016-05-05Feign如何實(shí)現(xiàn)第三方的HTTP請(qǐng)求
這篇文章主要介紹了Feign如何實(shí)現(xiàn)第三方的HTTP請(qǐng)求,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10SpringBoot中接收POST參數(shù)的幾種方式詳解
這篇文章主要介紹了SpringBoot中接收POST參數(shù)的幾種方式,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06詳解Java虛擬機(jī)管理的內(nèi)存運(yùn)行時(shí)數(shù)據(jù)區(qū)域
這篇文章主要介紹了詳解Java虛擬機(jī)管理的內(nèi)存運(yùn)行時(shí)數(shù)據(jù)區(qū)域的相關(guān)資料,需要的朋友可以參考下2017-03-03SpringBoot、mybatis返回樹結(jié)構(gòu)的數(shù)據(jù)實(shí)現(xiàn)
本文主要介紹了SpringBoot、mybatis返回樹結(jié)構(gòu)的數(shù)據(jù)實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04Java實(shí)現(xiàn)非阻塞式服務(wù)器的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用Java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的非阻塞式服務(wù)器,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,需要的可以參考一下2023-05-05intellij idea中spring boot properties文件不能自動(dòng)提示問題解決
這篇文章主要介紹了intellij idea中spring boot properties文件不能自動(dòng)提示問題解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02