異步方法調(diào)用
異步方法調(diào)用或異步方法模式是(多線程)面向?qū)ο蟪绦蛟O(shè)計(jì)中用于異步調(diào)用對象的潛在的長期運(yùn)行
方法的一種設(shè)計(jì)模式。在說異步方法調(diào)用時(shí),我們有必要再來看一下同步方法調(diào)用。
同步方法調(diào)用在程序繼續(xù)執(zhí)行之前需要等待同步方法全部執(zhí)行完畢返回結(jié)果。
同步調(diào)用是一種典型的阻塞式調(diào)用,無論如何我們只能等代上一個(gè)任務(wù)完成后,才能繼續(xù)后面的任務(wù)。
而異步方法調(diào)用,只需要發(fā)送調(diào)用任務(wù)的指令,調(diào)用者無需等待被調(diào)用的任務(wù)完全執(zhí)行完成,就
可以繼續(xù)執(zhí)行后面的任務(wù)。
Java中異步調(diào)用的處理方式
在Java中,一般情況下都是通過創(chuàng)建獨(dú)立的線程去完成異步調(diào)用的邏輯,主線程與其他線程執(zhí)行
不同的流程,從而避免主線程被阻塞。
Spring中的異步調(diào)用@Async
在Spring中,基于@Async標(biāo)注的方法,就被轉(zhuǎn)化為異步方法。這些方法在調(diào)用時(shí),會在獨(dú)立的線程
中執(zhí)行,調(diào)用者無需等待其調(diào)用完成,就可以繼續(xù)向下執(zhí)行。
配置開啟@Async
Java代碼開啟
@Configuration
@EnableAsync
public class SpringAsyncConfig { ... }
或
@SpringBootApplication
@EnableAsync
public class SpringApplication {
public static void main(String[] args) {
SpringApplication.run(Cs2Application.class, args);
}
}
XML配置開啟
<task:executor id="myexecutor" pool-size="5" />
<task:annotation-driven executor="myexecutor"/>
標(biāo)注方法
@Async標(biāo)注無返回值的方法
@Async //標(biāo)注使用
public void asyncMethodWithVoidReturnType() {
System.out.println("Execute Void Return Type Method");
}
@Async標(biāo)注有返回值的方法
@Async
public Future<String> asyncMethodWithReturnType() {
System.out.println("Execute Has Return Type Method");
try {
Thread.sleep(5000);
return new AsyncResult<String>("Return String");
} catch (InterruptedException e) {
//
}
return null;
}
這里方法的返回類型是Future接口,F(xiàn)uture接口是Java線程Future模式的實(shí)現(xiàn),用來進(jìn)行異步計(jì)算。
Future模式可以簡單的理解為,調(diào)用者將任務(wù)提交給Future,F(xiàn)uture去執(zhí)行任務(wù),在執(zhí)行期間
調(diào)用者可以繼續(xù)執(zhí)行其他任務(wù),在一段時(shí)間后,調(diào)用者可以通過Future獲取到任務(wù)的執(zhí)行結(jié)果。
獲取方法返回值:
Future<String> future = asyncService.asyncMethodWithReturnType();
while (true) {
if (future.isDone()) { //判斷是否執(zhí)行完畢
System.out.println("Receive Return Value" + future.get());
break;
}
System.out.println("Continue Waiting");
Thread.sleep(1000);
}
@Async方法中的異常處理
配置AsyncUncaughtExceptionHandler 捕獲無返回值方法中的異常
@EnableAsync
@Configuration
@Slf4j
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(8);
executor.setMaxPoolSize(16);
executor.setQueueCapacity(64);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setThreadNamePrefix("SpringAsyncThread-");
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SpringAsyncExceptionHandler();
}
class SpringAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {
log.error("Exception in async method - {}", throwable.getMessage());
}
}
}
有返回值的異步方法的異常捕獲
對于有返回值的異步方法,返回值應(yīng)當(dāng)是AsyncResult類的對象,或者是Future接口的子類,
這樣在調(diào)用Future的get()方法時(shí),就可以捕獲ExcecutionException。
@Async方法中的事務(wù)處理
在被@Async標(biāo)注的方法上同時(shí)有@Transactional標(biāo)注時(shí),由于其基于異步處理操作,在對數(shù)據(jù)庫進(jìn)行操作時(shí),將無法對
事務(wù)管理進(jìn)行控制。
如果方法內(nèi)的操作需要添加事務(wù)管理,可以將相關(guān)操作提取出單獨(dú)的方法,在該方法上添加@Transactional標(biāo)注。
注意
AsyncService中包含A(), B(), C()三個(gè)異步方法,
若在AsyncService的某一方法中調(diào)用A,B,C方法是無法異步執(zhí)行的。