系统中对大数据量的导入导出,是使用springboot的@Async来实现的异步多线程来处理的。但是最近发现导入任务后,导入任务函数要很久后才能启动。
起初是怀疑系统卡住或者出现了死锁,后台查询日志后发现任务虽然被延迟了,但是依然会被执行,只是延迟时间不确定。说明不是系统卡住或者死锁,只是线程没有启动而已。至于为什么线程不能被及时启动,这就是从@Async注解的实现机制来看了,springboot的这个异步任务,其实是使用内置的一个线程池来实现的,既然是线程池就存在线程池容量的问题,再加上最近确实代码更新了多个地方使用都在使用异步任务。所以大概率就是默认的线程池过小,不够用了,导致等待获取线程的时间过久造成了上述的问题。
为了解决问题,只能是自定义线程池,通过扩容来实现了。
线程池的配置类如下:
/**
* Copyright (C), 2017-2020,
* Filename: ExecutorConfig
* Author: xxxxx
* Date: 2023/2/14 14:39
* Description:〈线程池配置〉
* History:
* <author> <time> <version> <desc>
* 作者姓名 修改时间 版本号 描述
*/
@Configuration
@EnableAsync
public class ExecutorConfig {
@Value("${thread.core-pool-size:15}")
private int corePoolSize;
@Value("${thread.max-pool-size:150}")
private int maxPoolSize;
@Value("${thread.queue-capacity:10240}")
private int queueCapacity;
@Value("${thread.keep-alive-seconds:200}")
private int keepAliveSeconds;
private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class);
@Bean
public Executor asyncServiceExecutor() {
logger.info("start asyncServiceExecutor");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//设置核心线程数
executor.setCorePoolSize(corePoolSize);
//设置最大线程数
executor.setMaxPoolSize(maxPoolSize);
//线程池所使用的缓冲队列
executor.setQueueCapacity(queueCapacity);
//设置多余线程等待的时间,单位:秒
executor.setKeepAliveSeconds(keepAliveSeconds);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix("async-service-");
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
executor.initialize();
return executor;
}
}
然后在需要异步执行的函数上添加注解@Async("asyncServiceExecutor")就好了,注解中需要指定使用上述配置的线程池。