Spring:@Async注解和AsyncResult與CompletableFuture使用問題
@Async概述
Spring中用@Async注解標(biāo)記的方法,稱為異步方法,它會(huì)在調(diào)用方的當(dāng)前線程之外的獨(dú)立的線程中執(zhí)行,
其實(shí)就相當(dāng)于我們自己
new Thread(()-> System.out.println("hello world !"))這樣在另一個(gè)線程中去執(zhí)行相應(yīng)的業(yè)務(wù)邏輯
異步方法實(shí)際的執(zhí)行交給了 Spring 的 TaskExecutor 來完成。
@Async使用
- @Async注解如果用在類的方法上,則說明改方法是異步方法
- @Async注解如果用在類上,那么這個(gè)類所有的方法都是異步執(zhí)行的
- @Async注解方法的類對象應(yīng)該是Spring容器管理的bean對象
- 調(diào)用異步方法類上需要配置上注解@EnableAsync,或者是在啟動(dòng)類上加上@EnableAsync
@Async注意
- 默認(rèn)情況下(@EnableAsync注解的
mode=AdviceMode.PROXY),同一個(gè)類內(nèi)部沒有使用@Async注解修飾的方法調(diào)用@Async注解修飾的方法,是不會(huì)異步執(zhí)行的 - 如果想實(shí)現(xiàn)類內(nèi)部自調(diào)用也可以異步,則需要切換@EnableAsync注解的mode=
AdviceMode.ASPECTJ - 任意參數(shù)類型都是支持的,但是方法返回值必須是void或者Future類型
@Async代碼示例
使用1代碼實(shí)現(xiàn):調(diào)用異步方法類上配置@EnableAsync
import org.springframework.scheduling.annotation.Async;
public interface TestService {
@Async
void test();
}import com.example.service.TestService;
import org.springframework.stereotype.Service;
@Service
public class TestServiceImpl implements TestService {
@Override
public void test() {
//...
}
}調(diào)用異步方法的controller類
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping(value = "/test")
@EnableAsync
public class TestContoller {
@Autowired
private TestService testService;
@GetMapping(value = "/testAsync")
public void print() {
testService.test();
}
}如果我們?nèi)コ齌estController上的@EnableAsync或者new 一個(gè)TestService對象(該對象沒有加載進(jìn)Spring的容器中),那么TestController中的print()方法都會(huì)同步執(zhí)行,后臺打印日志也可以看到只有一個(gè)線程在執(zhí)行
使用2代碼實(shí)現(xiàn):在啟動(dòng)類上配置@EnableAsync
如果啟動(dòng)類上配置@EnableAsync,那么在上例代碼中,便不需要再在Controller上面加上@EnableAsync這個(gè)注解
入口類增加了 @EnableAsync 注解,主要是為了掃描范圍包下的所有 @Async 注解。
注意1代碼實(shí)現(xiàn):@Async沒有生效
@Async 修飾test()方法,test2()方法不修飾
public interface TestService {
@Async
void test();
void test2();
}public class TestServiceImpl implements TestService{
@Override
public void test() {
//...
}
@Override
public void test2() {
test();//自調(diào)用test()方法
}
}這種情況下“:test2()方法調(diào)用的test()方法并沒有異步執(zhí)行,只有一個(gè)線程
AsyncResult
Spring中提供了一個(gè) Future 接口的子類:AsyncResult,所以我們可以返回 AsyncResult 類型的值。
AsyncResult是異步方式,異步主要用于調(diào)用的代碼需要長時(shí)間運(yùn)行,才能返回結(jié)果的時(shí)候,可以不阻塞調(diào)用者
public class AsyncResult<V> implements ListenableFuture<V> {
private final V value;
private final ExecutionException executionException;
//...
}AsyncResult實(shí)現(xiàn)了ListenableFuture接口,該對象內(nèi)部有兩個(gè)屬性:返回值和異常信息。
public interface ListenableFuture<T> extends Future<T> {
void addCallback(ListenableFutureCallback<? super T> var1);
void addCallback(SuccessCallback<? super T> var1, FailureCallback var2);
}AsyncResult代碼示例
獲取異步方法返回值的實(shí)現(xiàn):返回String
public Future<String> test() throws Exception {
log.info("開始做任務(wù)");
long start = System.currentTimeMillis();
Thread.sleep(1000);
long end = System.currentTimeMillis();
log.info("完成任務(wù),耗時(shí):" + (end - start) + "毫秒");
return new AsyncResult<>("任務(wù)完成,耗時(shí)" + (end - start) + "毫秒");
}返回自定義類型的話,在上面的Future里面的String改為對應(yīng)的實(shí)體類
CompletableFuture
統(tǒng)計(jì)一下三個(gè)任務(wù)并發(fā)執(zhí)行共耗時(shí)多少,這就需要等到上述三個(gè)函數(shù)都完成調(diào)動(dòng)之后記錄時(shí)間,并計(jì)算結(jié)果。
也可以使用CompletableFuture來返回異步調(diào)用的結(jié)果
- 通過CompletableFuture.allOf(task1, task2, task3).join()實(shí)現(xiàn)三個(gè)異步任務(wù)都結(jié)束之前的阻塞效果
- 三個(gè)任務(wù)都完成之后,根據(jù)結(jié)束時(shí)間 - 開始時(shí)間,計(jì)算出三個(gè)任務(wù)并發(fā)執(zhí)行的總耗時(shí)。
CompletableFuture代碼示例
@Async
public CompletableFuture<String> doTaskOne() throws Exception {
log.info("開始做任務(wù)一");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("完成任務(wù)一,耗時(shí):" + (end - start) + "毫秒");
return CompletableFuture.completedFuture("任務(wù)一完成");
}@Test
public void test() throws Exception {
long start = System.currentTimeMillis();
CompletableFuture<String> task1 = asyncTasks.test();
CompletableFuture<String> task2 = asyncTasks.test();
CompletableFuture<String> task3 = asyncTasks.test();
CompletableFuture.allOf(task1, task2, task3).join();
long end = System.currentTimeMillis();
log.info("任務(wù)全部完成,總耗時(shí):" + (end - start) + "毫秒");
}線程池配置
自行谷歌或百度,spring線程池配置,基本上很詳細(xì)了
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring?Cloud?Hystrix原理與注意事項(xiàng)小結(jié)
本文介紹了Hystrix的基本概念、工作原理以及其在實(shí)際開發(fā)中的應(yīng)用方式,通過對Hystrix的深入學(xué)習(xí),開發(fā)者可以在分布式系統(tǒng)中實(shí)現(xiàn)精細(xì)的錯(cuò)誤處理機(jī)制,并能夠及時(shí)響應(yīng)系統(tǒng)中的異常,避免服務(wù)的連鎖崩潰,感興趣的朋友一起看看吧2025-03-03
你應(yīng)該知道的21個(gè)Java核心技術(shù)
Java的21個(gè)核心技術(shù)點(diǎn),你知道嗎?這篇文章主要為大家詳細(xì)介紹了Java核心技術(shù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
利用openoffice+jodconverter-code-3.0-bate4實(shí)現(xiàn)ppt轉(zhuǎn)圖片
這篇文章主要為大家詳細(xì)介紹了利用openoffice+jodconverter-code-3.0-bate4實(shí)現(xiàn)ppt轉(zhuǎn)圖片,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-07-07
Springboot配置文件相關(guān)語法及讀取方式詳解
本文主要介紹了Spring Boot中的兩種配置文件形式,即.properties文件和.yml/.yaml文件,詳細(xì)講解了這兩種文件的語法和讀取方式,同時(shí),還介紹了使用@ConfigurationProperties注解和Environment接口讀取配置文件的方法,并提供了具體的讀取示例2025-12-12

