Spring Boot 异步线程间数据传递
异步多线程传递数据
在实际开发中经常遇到需要在父子线程之间传递一些数据,比如用户信息,链路信息等等,可能第一想到的使用ThreadLocal
。但是ThreadLocal
不适用于线程池的情况下。如果你看过ThansmittableThreadLocal ,就会想到可以使用ttl
来实现。
线程池定义
@Bean("taskExecutor")
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor poolTaskExecutor = new ThreadPoolTaskExecutor();
poolTaskExecutor.setCorePoolSize(xx);
poolTaskExecutor.setMaxPoolSize(xx);
// 设置线程活跃时间(秒)
poolTaskExecutor.setKeepAliveSeconds(xx);
// 设置队列容量
poolTaskExecutor.setQueueCapacity(xx);
//设置TaskDecorator,用于解决父子线程间的数据复用
poolTaskExecutor.setTaskDecorator(new ContextTaskDecorator());
poolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
poolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
return poolTaskExecutor;
}
TaskDecorator
TaskDecorator
:官方 API的大致意思就是,这是一个执行回调方法的装饰器,主要应用于传递上下文,或者提供任务的监控/统计信息。
/**
* @description 上下文装饰器
*/
public class ContextTaskDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
//获取父线程的loginVal
LoginVal loginVal = OauthContext.get();
return () -> {
try {
// 将主线程的请求信息,设置到子线程中
OauthContext.set(loginVal);
// 执行子线程,这一步不要忘了
runnable.run();
} finally {
// 线程结束,清空这些信息,否则可能造成内存泄漏
OauthContext.clear();
}
};
}
}
OauthContext
- 引入
ttl
依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.14.2</version>
</dependency>
- OauthContext
/**
* @description 用户上下文信息
*/
public class OauthContext {
private static final TransmittableThreadLocal<LoginVal> loginValThreadLocal=new TransmittableThreadLocal<>();
public static LoginVal get(){
return loginValThreadLocal.get();
}
public static void set(LoginVal loginVal){
loginValThreadLocal.set(loginVal);
}
public static void clear(){
loginValThreadLocal.remove();
}
}
- 子线程获取示例
public void handlerAsync() {
log.info("父线程的用户信息:{}", OauthContext.get());
//执行异步任务,需要指定的线程池
CompletableFuture.runAsync(()-> log.info("子线程的用户信息:{}", OauthContext.get()),taskExecutor);
}