Spring Boot @Async 異步任務(wù)執(zhí)行方法
1、任務(wù)執(zhí)行和調(diào)度
Spring用TaskExecutor和TaskScheduler接口提供了異步執(zhí)行和調(diào)度任務(wù)的抽象。
Spring的TaskExecutor和java.util.concurrent.Executor接口時(shí)一樣的,這個(gè)接口只有一個(gè)方法execute(Runnable task)。
1.1、TaskExecutor類型
Spring已經(jīng)內(nèi)置了許多TaskExecutor的實(shí)現(xiàn),你沒有必要自己去實(shí)現(xiàn):
- SimpleAsyncTaskExecutor 這種實(shí)現(xiàn)不會(huì)重用任何線程,每次調(diào)用都會(huì)創(chuàng)建一個(gè)新的線程。
- SyncTaskExecutor 這種實(shí)現(xiàn)不會(huì)異步的執(zhí)行
- ConcurrentTaskExecutor 這種實(shí)現(xiàn)是java.util.concurrent.Executor的一個(gè)adapter。
- SimpleThreadPoolTaskExecutor 這種實(shí)現(xiàn)實(shí)際上是Quartz的SimpleThreadPool的一個(gè)子類,它監(jiān)聽Spring的聲明周期回調(diào)。
- ThreadPoolTaskExecutor 這是最常用最通用的一種實(shí)現(xiàn)。它包含了java.util.concurrent.ThreadPoolExecutor的屬性,并且用TaskExecutor進(jìn)行包裝。
1.2、注解支持調(diào)度和異步執(zhí)行
To enable support for @Scheduled and @Async annotations add @EnableScheduling and @EnableAsync to one of your
@Configuration classes:
@Configuration
@EnableAsync
@EnableScheduling
public class AppConfig {
}
特別注意
The default advice mode for processing @Async annotations is "proxy" which allows for interception of calls through the proxy only; local calls within the same class cannot get intercepted that way. For a more advanced mode of interception, consider switching to "aspectj" mode in combination with compile-time or load-time weaving.
默認(rèn)是用代理去處理@Async的,因此,相同類中的方法調(diào)用帶@Async的方法是無法異步的,這種情況仍然是同步。
舉個(gè)例子:下面這種,在外部直接調(diào)用sayHi()是可以異步執(zhí)行的,而調(diào)用sayHello()時(shí)sayHi()仍然是同步執(zhí)行
public class A {
public void sayHello() {
sayHi();
}
@Async
public void sayHi() {
}
}
1.3、@Async注解
在方法上加@Async注解表示這是一個(gè)異步調(diào)用。換句話說,方法的調(diào)用者會(huì)立即得到返回,并且實(shí)際的方法執(zhí)行是想Spring的TaskExecutor提交了一個(gè)任務(wù)。
In other words, the caller will return immediately upon invocation and the actual execution of the method will occur in a task that has been submitted to a Spring TaskExecutor.
@Async
void doSomething() {
// this will be executed asynchronously
}
@Async
void doSomething(String s) {
// this will be executed asynchronously
}
@Async
Future<String> returnSomething(int i) {
// this will be executed asynchronously
}
注意:
@Async methods may not only declare a regular java.util.concurrent.Future return type but also Spring's org.springframework.util.concurrent.ListenableFuture or, as of Spring 4.2, JDK 8's java.util.concurrent.CompletableFuture: for richer interaction with the asynchronous task and for immediate composition with further processing steps.
1.4、@Async限定Executor
默認(rèn)情況下,當(dāng)在方法上加@Async注解時(shí),將會(huì)使用一個(gè)支持注解驅(qū)動(dòng)的Executor。然而,@Async注解的value值可以指定一個(gè)別的Executor
@Async("otherExecutor")
void doSomething(String s) {
// this will be executed asynchronously by "otherExecutor"
}
這里,otherExecutor是Spring容器中任意Executor bean的名字。
1.5、@Async異常管理
當(dāng)一個(gè)@Async方法有一個(gè)Future類型的返回值時(shí),就很容易管理在調(diào)Future的get()方法獲取任務(wù)的執(zhí)行結(jié)果時(shí)拋出的異常。如果返回類型是void,那么異常是不會(huì)被捕獲到的。
public class MyAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
// handle exception
}
}
2、線程池配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
@EnableAsync
public class TaskExecutorConfig {
private Integer corePoolSize = 30;
private Integer maxPoolSize = 50;
private Integer keepAliveSeconds = 300;
// private Integer queueCapacity = 2000;
@Bean("myThreadPoolTaskExecutor")
public ThreadPoolTaskExecutor myThreadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setKeepAliveSeconds(keepAliveSeconds);
// executor.setQueueCapacity(queueCapacity);
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.initialize();
return executor;
}
}
調(diào)用
@Async("myThreadPoolTaskExecutor")
@Override
public void present(CouponPresentLogEntity entity) {
try {
CouponBaseResponse rst = couponSendRpcService.send(entity.getUserId(), entity.getCouponBatchKey(), "1", entity.getVendorId());
if (null != rst && rst.isSuccess()) {
entity.setStatus(PresentStatusEnum.SUCCESS.getType());
}else {
String reason = (null == rst) ? "響應(yīng)異常" : rst.getMsg();
entity.setFailureReason(reason);
entity.setStatus(PresentStatusEnum.FAILURE.getType());
}
}catch (Exception ex) {
log.error(ex.getMessage(), ex);
entity.setFailureReason(ex.getMessage());
entity.setStatus(PresentStatusEnum.FAILURE.getType());
}
couponPresentLogDao.update(entity);
}
結(jié)果
[INFO ] 2018-05-09 16:27:39.887 [myThreadPoolTaskExecutor-1] [com.ourhours.coupon.rpc.dubbo.ReceiveLogFilter] - receive method-name:send; arguments:[10046031,"4d7cc32f8f7e4b00bca56f6bf4b3b658","1",10001]
[INFO ] 2018-05-09 16:27:39.889 [myThreadPoolTaskExecutor-2] [com.ourhours.coupon.rpc.dubbo.ReceiveLogFilter] - receive method-name:send; arguments:[10046031,"4d7cc32f8f7e4b00bca56f6bf4b3b658","1",10001]
參考:
Spring Framework Reference Documentation 4.3.17.RELEASE

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)(使用數(shù)據(jù)庫)
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)學(xué)生信息管理系統(tǒng),使用數(shù)據(jù)庫,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01
Java實(shí)現(xiàn)矩陣乘法以及優(yōu)化的方法實(shí)例
這篇文章主要給大家介紹了關(guān)于Java實(shí)現(xiàn)矩陣乘法以及優(yōu)化的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
JPA?@ManyToMany?報(bào)錯(cuò)StackOverflowError的解決
這篇文章主要介紹了JPA?@ManyToMany?報(bào)錯(cuò)StackOverflowError的解決,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
Java實(shí)戰(zhàn)之仿天貓商城系統(tǒng)的實(shí)現(xiàn)
這篇文章主要介紹了如何利用Java制作一個(gè)基于SSM框架的迷你天貓商城系統(tǒng),文中采用的技術(shù)有JSP、Springboot、SpringMVC、Spring等,需要的可以參考一下2022-03-03
Java多線程之線程通信生產(chǎn)者消費(fèi)者模式及等待喚醒機(jī)制代碼詳解
這篇文章主要介紹了Java多線程之線程通信生產(chǎn)者消費(fèi)者模式及等待喚醒機(jī)制代碼詳解,具有一定參考價(jià)值,需要的朋友可以了解下。2017-10-10

