1 配置自己的线程池
@Configuration
@EnableAsync
public class ThreadPoolConfig
{
private int corePoolSize = 50;
private int maxPoolSize = 200;
private int queueCapacity = 1000;
private int keepAliveSeconds = 300;
@Bean(name = "threadPoolTaskExecutor")
public ThreadPoolTaskExecutor threadPoolTaskExecutor()
{
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setMaxPoolSize(maxPoolSize);
executor.setCorePoolSize(corePoolSize);
executor.setKeepAliveSeconds(keepAliveSeconds);
executor.setQueueCapacity(queueCapacity);
executor.setThreadNamePrefix("ThreadPoolTaskExecutor======>");
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(5);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
- 一定要自己配置,不要使用
SpringBoot
自带的,Spring
默认的线程池没有上限,并发多时,可能会OOM
。并且不是线程重用,每次都会新建一个线程。ThreadPoolTaskExecutor
会重用线程,节省创建线程的资源。因此,在使用ThreadLocal
时,也要及时清理缓存,否则,会获取到上一个任务的参数。
2 使用
2.1 在Service层使用
Controller
层直接返回结果,具体的业务,由其他线程执行。
@Override
@Async("threadPoolTaskExecutor")
public void concatAB() {
......
}
2.2 多线程中使用事务的写法
- 事务放到其他方法
@Transactional
,然后调用。
@Override
@Async("threadPoolTaskExecutor")
public void concatAB() {
addChange()
......
}
@Transactional(rollbackFor = Exception.class,isolation = Isolation.SERIALIZABLE)
public void addChange(){
.......
}
2.3 方法内多线程
- 同一个类下调用内部方法无法实现多线程,下面这种方法是错误的。因为,
@Async
是通过AOP实现的,方法没调用,没有进入切面。所以,无法实现多线程。
@Override
public void concatAB() {
addChange()
......
}
@Async("threadPoolTaskExecutor")
public void addChange(){
.......
}
@Autowired
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
@Override
public void concatAB() {
threadPoolTaskExecutor.execute(() -> {
....
});
}
3 线程池与并行流的选取
IO
密集型的业务,选取线程池来完成。(例如,连接数据库之类的操作)
cpu
密集型的业务,选取并行流allelesvs.parallelStream()
的方式处理。(例如,计算类、过滤、求和、分组等)