ThreadLocal InheritableThreadLocal TransmittableThreadLocal简单使用
创始人
2024-04-07 02:14:40
0

需求: 主线程向异步线程传递用户token信息,

关于线程之间数据传递的几个关键对象,

  • 主线程向子线程传递时,可以通过InheritableThreadLocal对象
  • 使用ExecutorService或者CompletableFuture执行时, 线程池内线程复用的原因,同时Thread对象内的inheritableThreadLocals值一是null,所以无法使用InheritableThreadLocal对象
  • TransmittableThreadLocal为比较适合解决方案 官方地址
  • 异步线程RequestContextHolder为空问题

先上例子

public static final ThreadLocal context = new ThreadLocal<>();//
public static final ThreadLocal context1 = new TransmittableThreadLocal<>();//
public static final ThreadLocal context2 = new InheritableThreadLocal<>();public static void main(String[] args) {context.set("A");context1.set("B");context2.set("C");CompletableFuture.runAsync(() -> {//ThreadLocal 线程之间隔离String mm = context.get();log.info("1: {}",mm);});CompletableFuture.runAsync(TtlRunnable.get(() -> { //TransmittableThreadLocal可以取到String mm = context1.get();log.info("2: {}",mm);}));CompletableFuture.runAsync(() -> { //取不到String mm = context2.get();log.info("3: {}",mm);});Thread thread = new Thread(() -> { // 子线程,正常可以取到String mm = context2.get();log.info("4: {}",mm);});thread.start();}
[ForkJoinPool.commonPool-worker-1] INFO cn.me56.integration.stat.StatApiController - 1: null
[ForkJoinPool.commonPool-worker-2] INFO cn.me56.integration.stat.StatApiController - 2: A
[ForkJoinPool.commonPool-worker-1] INFO cn.me56.integration.stat.StatApiController - 3: null
[Thread-0] INFO cn.me56.integration.stat.StatApiController - 4: C

这里是InheritableThreadLocal使用子线程的例子:

public class InheritableThreadLocalDemo {private static ThreadLocal threadLocal = new InheritableThreadLocal<>();public static void main(String[] args) {threadLocal.set("mainThread");System.out.println("value:"+threadLocal.get());Thread thread = new Thread(new Runnable() { //子线程,可以取到@Overridepublic void run() {String value = threadLocal.get();System.out.println("value:"+value);}});thread.start();}}
value:mainThread
value:mainThread

TransmittableThreadLocal,简单使用方法

public static final ThreadLocal context1 = new TransmittableThreadLocal<>();//
CompletableFuture.runAsync(TtlRunnable.get(() -> { //do something...
}));
或者
CompletableFuture.supplyAsync(TtlWrappers.wrapSupplier(()-> {//do something...return "return value";}) );
或者
java agent 方式 

线程之间可以传递数据之后,再看下RequestContextHolder为空问题, 初步是想把request对象传给异步线程, 尝试之后觉得此方案不合理,没必要把整个request传进去

  1. 使用如下方式.设置之后,进入异步线程,RequestContextHolder.getRequestAttributes()也还是空的…
RequestContextHolder.setRequestAttributes(RequestContextHolder.getRequestAttributes(), true);
  1. 如下使用如下方式.在主线程关闭之后,子线程想获取request内参数,还是空的,如果是copy一个request,应该就能正常了
CompletableFuture.runAsync(() -> { RequestContextHolder.setRequestAttributes(...);//do something...
});

最终,因为业务需要完成的,是希望把长时间统计/查询接口,在系统资源有限的情况下,以时间换空间,拆分成多个子任务,所以这里线程之间传参仅仅只用了MDC.put/get方式简单实现了一下

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【PdgCntEditor】解... 一、问题背景 大部分的图书对应的PDF,目录中的页码并非PDF中直接索引的页码...