SpringBoot异步线程,父子线程数据传递的5种姿势( 三 )

Test2Controller/*** 使用InheritableThreadLocal方式* @return* @throws InterruptedException* @throws ExecutionException*/@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
/** *使用TransmittableThreadLocal存储线程之间共享的数据变量,如登录的用户信息 */public class UserTransmittableUtils {private staticfinal TransmittableThreadLocal<String> userLocal=new TransmittableThreadLocal<>();public staticString getUserId(){return userLocal.get();}public static void setUserId(String userId){userLocal.set(userId);}public static void clear(){userLocal.remove();}}}复制代码AsyncServiceImpl/*** 使用TransmittableThreadLocal获取主线程传递的数据* @return* @throws InterruptedException*/@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/*** 使用TransmittableThreadLocal方式* @return* @throws InterruptedException* @throws ExecutionException*/@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进行优化封装 。为什么要封装,有兴趣的可以去学习《 加强版ThreadLocal之阿里开源TransmittableThreadLocal学习 》
本人推荐使用方案5,哈哈 。
简答说一下InheritableThreadLocalpublic 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() {@Overridepublic void run() {System.out.println("打印4:"+local.get());}}).start();}复制代码运行结果如下
打印2:2打印1:1打印3:1打印4:2复制代码分析: 分析打印3为什么是1,InheritableThreadLocal的继承性是在new Thread创建子线程时候在构造函数内把父线程内线程变量拷贝到子线程内部的 。为了不在创建新线程耗费资源,我们一般会用线程池,线程池的线程会复用,那么线程中的ThreadLocal便不对了,可能是旧的,因为线程是旧的 。

【SpringBoot异步线程,父子线程数据传递的5种姿势】


推荐阅读