ruoyi-vue使用线程池进行异步开发
1.异步线程池工具类
@Configuration
public class ThreadExecutorUtils
{
// 核心线程池大小
private int corePoolSize = 50;
// 最大可创建的线程数
private int maxPoolSize = 200;
// 队列最大长度
private int queueCapacity = 1000;
// 线程池维护线程所允许的空闲时间
private int keepAliveSeconds = 300;
@Bean(name = "taskExecutor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程池大小
executor.setCorePoolSize(corePoolSize);
//最大线程数
executor.setMaxPoolSize(maxPoolSize);
//队列容量
executor.setQueueCapacity(queueCapacity);
//活跃时间
executor.setKeepAliveSeconds(keepAliveSeconds);
//线程名字前缀
executor.setThreadNamePrefix("ty-async-");
// setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务
// CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
2.在需要使用异步操作的service实现类注入上面的类
@Autowired
private ThreadExecutorUtils threadPoolTaskExecutor;
3.使用线程池进行异步操作
Executor executor = threadPoolTaskExecutor.getAsyncExecutor();
//addVisitHistory为本类中定义的一个异步执行的业务方法
executor.execute(() -> addVisitHistory(userId, spuId));
需要注意的地方:如果项目采用多数据源,在异步线程中,由于多数据源的动态切换通常依赖于线程本地变量(如 ThreadLocal
),而异步线程会丢失主线程的上下文(包括 ThreadLocal
中的数据源信息),因此需要额外的处理来确保数据源的一致性。
下面介绍一种示例处理方法:
// 获取当前数据源
String currentDataSource = DataSourceContextHolder.getDataSource();
// 创建异步任务
CompletableFuture.runAsync(() -> {
// 在异步线程中设置数据源
DataSourceContextHolder.setDataSource(currentDataSource);
try {
// 执行业务逻辑
someService.doSomething();
} finally {
// 清除数据源
DataSourceContextHolder.clearDataSource();
}
}, executor);
优点:
-
简单直接,易于理解。
-
适用于少量异步任务的场景。
缺点:
-
需要手动传递和设置数据源,代码侵入性较强。
-
如果异步任务嵌套较多,容易遗漏数据源的设置