差点被几篇文带偏,在做深入了解后做以下一些纪要。
几个要点:
1.这俩都是Spring为我们提供的可以实现异步效果的工具;
2.ThreadPoolTaskExecutor可以理解为是封装了ThreadPoolExecutor(java提供的线程池类),在基于Spring的环境下,用前者会更舒服;
3,@Async可以很简单的实现异步调用效果,但如果你想用线程池去实现,那和@Async没啥关系了。
@Async使用示例:
首先在启动类加上@EnableAsync注解,在你需要异步的业务方法上加上该注解可以了(也可以加在类上,但一般我们修饰方法更多),该方法应该封装在一个bean中,即它所属的类应该加上@Component注解。然后在外界引入这个类的依赖,去调用你的异步方法即可。
@Component
public class AsyncMethods {
// 异步方法
@Async
public void fuck {
//......
}
}
@Service
public class TempService {
@Resource
AsyncMethods asyncMethods;
// 异步方法的调用者
public void doFuck {
// 异步执行
asyncMethods.fuck();
}
}
注意以下几点会使@Async注解失效(引用过来的,部分未自己验证):
1.异步方法使用static修饰;
2.异步类没有使用@Component注解(或其他注解)导致spring无法扫描到异步类;
3.异步方法不能与被调用的异步方法在同一个类中;
4.类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象;
5.如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解;
ThreadPoolTaskExecutor使用示例:
可以使用原生的spring xml方式配置该线程池,也可以使用SpringBoot提供的代码注解方式配置之,推荐使用代码配置类方式:
package com.ctsi.eqiyun.base.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
@EnableAsync
public class ThreadPoolTaskConfig {
// 核心线程数(默认线程数)
private static final int CORE_POOL_SIZE = 20;
// 最大线程数
private static final int MAX_POOL_SIZE = 100;
// 允许线程空闲时间(单位:默认为秒)
private static final int KEEP_ALIVE_TIME = 10;
// 缓冲队列大小
private static final int QUEUE_CAPACITY = 200;
// 线程池名前缀
private static final String THREAD_NAME_PREFIX = "Async-Service-";
// bean的名称,默认为首字母小写的方法名
@Bean("asyncTaskExecutor")
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(CORE_POOL_SIZE);
executor.setMaxPoolSize(MAX_POOL_SIZE);
executor.setQueueCapacity(QUEUE_CAPACITY);
executor.setKeepAliveSeconds(KEEP_ALIVE_TIME);
executor.setThreadNamePrefix(THREAD_NAME_PREFIX);
// 线程池对拒绝任务的处理策略
// CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
executor.initialize();
return executor;
}
}
在需要使用线程池的地方引入我们配置的线程池bean,调用其excute方法实现线程池级别的异步调用:
@Service
public class TempService {
@Resource(name = "asyncTaskExecutor")
ThreadPoolTaskExecutor taskExcutor;
public void doSomething {
taskExcutor.excute(() -> {
// long time operation......
});
}
}
另外值得一提的是实际上想实现异步执行一些实时性要求不高且耗时较长的业务时,有很多方法可以选择,譬如最基本的extends Thread或者implements Runable亦或者本文记录的@Async注解等等,当我们的异步操作比较频繁,需要考虑到资源节省和复用等事宜时,就需要使用线程池了,而线程池也有很多选择,此文记录的ThreadPoolTaskExecutor只是Spring为我们提供的一个线程池。
ThreadPoolTaskExecutor和@Async注解没有直接关系,本文放一起记录只是因为差点受了另一篇文章的误导。
搬砖中,若有错误或需要补充的点,欢迎指出~



