SpringBoot父子线程数据传递的五种方案介绍
方案1.ThreadLocal+TaskDecorator
用户工具类 UserUtils
public class UserUtils {
private static final ThreadLocal<String> userLocal=new ThreadLocal<>();
public static String getUserId(){
return userLocal.get();
}
public static void setUserId(String userId){
userLocal.set(userId);
}
public static void clear(){
userLocal.remove();
}
}
自定义CustomTaskDecorator
public class CustomTaskDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
// 获取主线程中的请求信息(我们的用户信息也放在里面)
String robotId = UserUtils.getUserId();
System.out.println(robotId);
return () -> {
try {
// 将主线程的请求信息,设置到子线程中
UserUtils.setUserId(robotId);
// 执行子线程,这一步不要忘了
runnable.run();
} finally {
// 线程结束,清空这些信息,否则可能造成内存泄漏
UserUtils.clear();
}
};
}
}
ExecutorConfig
在原来的基础上增加 executor.setTaskDecorator(new CustomTaskDecorator());
@Bean(name = "asyncServiceExecutor")
public Executor asyncServiceExecutor() {
log.info("start asyncServiceExecutor----------------");
//ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//使用可视化运行状态的线程池
ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(corePoolSize);
//配置最大线程数
executor.setMaxPoolSize(maxPoolSize);
//配置队列大小
executor.setQueueCapacity(queueCapacity);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix(namePrefix);
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//增加线程池修饰类
executor.setTaskDecorator(new CustomTaskDecorator());
//增加MDC的线程池修饰类
//executor.setTaskDecorator(new MDCTaskDecorator());
//执行初始化
executor.initialize();
log.info("end asyncServiceExecutor------------");
return executor;
}
AsyncServiceImpl
@Async("asyncServiceExecutor")
public CompletableFuture<String> executeValueAsync2() throws InterruptedException {
log.info("start executeValueAsync");
System.out.println("异步线程执行返回结果......+");
log.info("end executeValueAsync");
return CompletableFuture.completedFuture(UserUtils.getUserId());
}
Test2Controller
@GetMapping("/test2")
public String test2() throws InterruptedException, ExecutionException {
UserUtils.setUserId("123456");
CompletableFuture<String> completableFuture = asyncService.executeValueAsync2();
String s = completableFuture.get();
return s;
}
方案2.RequestContextHolder+TaskDecorator
自定义CustomTaskDecorator
public class CustomTaskDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
// 获取主线程中的请求信息(我们的用户信息也放在里面)
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
return () -> {
try {
// 将主线程的请求信息,设置到子线程中
RequestContextHolder.setRequestAttributes(attributes);
// 执行子线程,这一步不要忘了
runnable.run();
} finally {
// 线程结束,清空这些信息,否则可能造成内存泄漏
RequestContextHolder.resetRequestAttributes();
}
};
}
}
ExecutorConfig
在原来的基础上增加 executor.setTaskDecorator(new CustomTaskDecorator());
@Bean(name = "asyncServiceExecutor")
public Executor asyncServiceExecutor() {
log.info("start asyncServiceExecutor----------------");
//ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//使用可视化运行状态的线程池
ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(corePoolSize);
//配置最大线程数
executor.setMaxPoolSize(maxPoolSize);
//配置队列大小
executor.setQueueCapacity(queueCapacity);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix(namePrefix);
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//增加线程池修饰类
executor.setTaskDecorator(new CustomTaskDecorator());
//增加MDC的线程池修饰类
//executor.setTaskDecorator(new MDCTaskDecorator());
//执行初始化
executor.initialize();
log.info("end asyncServiceExecutor------------");
return executor;
}
AsyncServiceImpl
@Async("asyncServiceExecutor")
public CompletableFuture<String> executeValueAsync3() throws InterruptedException {
log.info("start executeValueAsync");
System.out.println("异步线程执行返回结果......+");
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
Object userId = attributes.getAttribute("userId", 0);
log.info("end executeValueAsync");
return CompletableFuture.completedFuture(userId.toString());
}
Test2Controller
@GetMapping("/test3")
public String test3() throws InterruptedException, ExecutionException {
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
attributes.setAttribute("userId","123456",0);
CompletableFuture<String> completableFuture = asyncService.executeValueAsync3();
String s = completableFuture.get();
return s;
}
方案3.MDC+TaskDecorator
自定义MDCTaskDecorator
public class MDCTaskDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
// 获取主线程中的请求信息(我们的用户信息也放在里面)
String userId = MDC.get("userId");
Map<String, String> copyOfContextMap = MDC.getCopyOfContextMap();
System.out.println(copyOfContextMap);
return () -> {
try {
// 将主线程的请求信息,设置到子线程中
MDC.put("userId",userId);
// 执行子线程,这一步不要忘了
runnable.run();
} finally {
// 线程结束,清空这些信息,否则可能造成内存泄漏
MDC.clear();
}
};
}
}
ExecutorConfig
在原来的基础上增加 executor.setTaskDecorator(new MDCTaskDecorator());
@Bean(name = "asyncServiceExecutor")
public Executor asyncServiceExecutor() {
log.info("start asyncServiceExecutor----------------");
//ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//使用可视化运行状态的线程池
ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(corePoolSize);
//配置最大线程数
executor.setMaxPoolSize(maxPoolSize);
//配置队列大小
executor.setQueueCapacity(queueCapacity);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix(namePrefix);
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//增加MDC的线程池修饰类
executor.setTaskDecorator(new MDCTaskDecorator());
//执行初始化
executor.initialize();
log.info("end asyncServiceExecutor------------");
return executor;
}
AsyncServiceImpl
@Async("asyncServiceExecutor")
public CompletableFuture<String> executeValueAsync5() throws InterruptedException {
log.info("start executeValueAsync");
System.out.println("异步线程执行返回结果......+");
log.info("end executeValueAsync");
return CompletableFuture.completedFuture(MDC.get("userId"));
}
Test2Controller
@GetMapping("/test5")
public String test5() throws InterruptedException, ExecutionException {
MDC.put("userId","123456");
CompletableFuture<String> completableFuture = asyncService.executeValueAsync5();
String s = completableFuture.get();
return s;
}
方案4.InheritableThreadLocal
用户工具类 UserInheritableUtils
/
public class UserInheritableUtils {
private static final InheritableThreadLocal<String> userLocal=new InheritableThreadLocal<>();
public static String getUserId(){
return userLocal.get();
}
public static void setUserId(String userId){
userLocal.set(userId);
}
public static void clear(){
userLocal.remove();
}
}
AsyncServiceImpl
@Async("asyncServiceExecutor")
public CompletableFuture<String> executeValueAsync4() throws InterruptedException {
log.info("start executeValueAsync");
System.out.println("异步线程执行返回结果......+");
log.info("end executeValueAsync");
return CompletableFuture.completedFuture(UserInheritableUtils.getUserId());
}
Test2Controller
@GetMapping("/test4")
public String test4(@RequestParam("userId") String userId) throws InterruptedException, ExecutionException {
UserInheritableUtils.setUserId(userId);
CompletableFuture<String> completableFuture = asyncService.executeValueAsync4();
String s = completableFuture.get();
return s;
}
方案5.TransmittableThreadLocal
用户工具类 UserTransmittableUtils
public class UserTransmittableUtils {
private static final TransmittableThreadLocal<String> userLocal=new TransmittableThreadLocal<>();
public static String getUserId(){
return userLocal.get();
}
public static void setUserId(String userId){
userLocal.set(userId);
}
public static void clear(){
userLocal.remove();
}
}
}
AsyncServiceImpl
@Async("asyncServiceExecutor")
public CompletableFuture<String> executeValueAsync6() throws InterruptedException {
log.info("start executeValueAsync");
System.out.println("异步线程执行返回结果......+");
log.info("end executeValueAsync");
return CompletableFuture.completedFuture(UserTransmittableUtils.getUserId());
}
Test2Controller
@GetMapping("/test6")
public String test6() throws InterruptedException, ExecutionException {
UserTransmittableUtils.setUserId("123456");
CompletableFuture<String> completableFuture = asyncService.executeValueAsync6();
String s = completableFuture.get();
return s;
}
maven依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.12.1</version>
</dependency>
方案对比
方案1,方案2,方案3主要是借助TaskDecorator进行父子线程之间传递数据。其中MDC方案主要借鉴于MDC的日志跟踪的思想来实现,关于MDC相关的日志跟踪后续会学习分享
方案4和方案5使用InheritableThreadLocal和TransmittableThreadLocal来实现,其中TransmittableThreadLocal是阿里InheritableThreadLocal进行优化封装。
本人推荐使用方案5,哈哈。
简答说一下InheritableThreadLocal
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(1,1,1,
TimeUnit.MINUTES,new ArrayBlockingQueue<>(1));
ThreadLocal local = new InheritableThreadLocal();
local.set(1);
executor.execute(()->{
System.out.println("打印1:"+local.get());
});
local.set(2);
System.out.println("打印2:"+local.get());
executor.execute(()->{
System.out.println("打印3:"+local.get());
});
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("打印4:"+local.get());
}
}).start();
}
运行结果如下
打印2:2
打印1:1
打印3:1
打印4:2
分析: 分析打印3为什么是1,InheritableThreadLocal的继承性是在new Thread创建子线程时候在构造函数内把父线程内线程变量拷贝到子线程内部的。 为了不在创建新线程耗费资源,我们一般会用线程池,线程池的线程会复用,那么线程中的ThreadLocal便不对了,可能是旧的,因为线程是旧的。
总结
上面的的方案你学会了么
到此这篇关于SpringBoot父子线程数据传递的五种方案介绍的文章就介绍到这了,更多相关SpringBoot数据传递内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341