Spring封装了一个异步方法的实现,使得方法可以在单独的线程中异步执行,提高系统的并发能力和响应性能。
注解 | 说明 |
---|---|
@Async |
将方法标记为异步执行的方法,在方法上添加@Async 注解后,方法的调用将会在一个单独的线程中异步执行。 |
@EnableAsync |
在Spring配置类上使用该注解来启用异步处理功能 |
static
修饰@Component
注解(或其他注解注入Spring容器),否则导致Spring无法扫描到异步类@Autowired
或@Resource
等注解自动注入,不能自己手动new对象@EnableAsync
注解开启异步注意:如果报错Null return value from advice does not match primitive return type for
,需要将异步方法的返回值改为包装类,因为框架内部做了AOP处理,不管是cglib代理还是jdk代理,你的返回值都必须是包装类。
1、在启动类添加注解@EnableAsync
用于异步执行注解,并且使用spring默认线程池;也可以使用配置类开启,并且自定义线程池
@Configuration
@EnableAsync
public class AsyncThreadPoolConfig {
/**
* 默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,
* 当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
* 当队列满了,就继续创建线程,当线程数量大于等于maxPoolSize后,开始使用拒绝策略拒绝
*/
/** 核心线程数(默认线程数) */
private static final int corePoolSize = 20;
/** 最大线程数 */
private static final int maxPoolSize = 100;
/** 允许线程空闲时间(单位:默认为秒) */
private static final int keepAliveTime = 10;
/** 缓冲队列大小 */
private static final int queueCapacity = 200;
/** 线程池名前缀 */
private static final String threadNamePrefix = "Async-Service-";
@Bean("taskExecutor") // 默认Spring会找这个名字的线程池
public ThreadPoolTaskExecutor taskExecutor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(keepAliveTime);
executor.setThreadNamePrefix(threadNamePrefix);
// 线程池对拒绝任务的处理策略
// CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
executor.initialize();
return executor;
}
}
2、在需要异步执行的方法上添加注解@Async()
,value为使用的线程池,不写则为默认线程池byName = taskExcutor
@Service
public class TranTest2Service {
Logger log = LoggerFactory.getLogger(TranTest2Service.class);
// 使用自定义线程池
@Async("taskExecutor")
public void sendMessage1() throws InterruptedException {
// business
}
@Async("taskExecutor")
public void sendMessage2() throws InterruptedException {
// business
}
}