概叙
科普文: Java web应用性能分析之【java线程池中线程共享数据总结】-CSDN博客
科普:一文搞懂ThreadLocal_threadlocal线程池-CSDN博客
实战:一文搞懂InheritableThreadLocal_inheritablethreadlocal原理-CSDN博客
科普文:TransmittableThreadLocal通过javaAgent实现线程传递并支持ForkJoin-CSDN博客
科普文:TransmittableThreadLocal线程间传递逻辑示例解析_transmittablethreadlocal 实战-CSDN博客
前面我们对线程共享、ThreadLocal、InheritableThreadLocal、TransmittableThreadLocal都有过归纳梳理,关于线程共享建议如下。
最佳实践和建议:
-
最小化共享:尽可能减少不同线程间共享的数据量。如果可能,考虑将数据封装在每个任务中处理。
-
不可变对象:使用不可变对象可以避免修改共享状态的问题。例如,使用
String
而不是可变的StringBuilder
。 -
线程局部变量(ThreadLocal):当每个线程需要自己的数据副本时,可以使用
ThreadLocal
。但要注意过度使用可能会导致内存消耗过多。 -
适当的同步策略:选择合适的同步机制,例如在需要频繁读操作时使用读写锁(
ReadWriteLock
)。 -
避免在锁外暴露内部状态:确保在锁保护的代码块中不暴露任何内部状态给调用者,以防止在锁释放后状态被修改。例如,返回一个副本而不是直接返回对象引用。
public synchronized List<String> getItemsCopy() { // 使用同步方法返回副本而不是直接返回列表引用。
return new ArrayList<>(items); // 创建一个列表的副本返回。
}
下面我们从原理、核心类、用法、优缺点、适用场景等方面对ThreadLocal、InheritableThreadLocal、TransmittableThreadLocal做一个小结。
小结:ThreadLocal、InheritableThreadLocal、TransmittableThreadLocal
一、核心原理与逻辑图
类别 | 核心原理 | 核心类与逻辑图 |
---|---|---|
ThreadLocal | 每个线程通过 Thread 内部的 ThreadLocalMap 存储数据,键为 ThreadLocal 实例,值为线程私有数据。通过弱引用解决内存泄漏问题,但需手动调用 remove() 清理。 | 核心类:ThreadLocal 、ThreadLocalMap 逻辑图: 线程 → ThreadLocalMap → Entry(ThreadLocal弱引用, 值) |
InheritableThreadLocal | 继承 ThreadLocal ,在子线程创建时,通过 Thread.init() 方法复制父线程的 inheritableThreadLocals 数据到子线程的 ThreadLocalMap 中,实现父子线程数据传递。 | 核心类:InheritableThreadLocal 逻辑图: 父线程 → inheritableThreadLocals → 子线程初始化时复制 → 子线程的 ThreadLocalMap |
TransmittableThreadLocal (TTL) | 扩展 InheritableThreadLocal ,通过包装任务(TtlRunnable /TtlCallable )在执行前捕获当前线程的上下文,并在任务执行时恢复。利用 Transmitter 类管理上下文传递逻辑,解决线程池复用线程导致的数据丢失问题。 | 核心类:TransmittableThreadLocal 、TtlRunnable 、Transmitter 逻辑图: 主线程 → 任务包装( TtlRunnable ) → 线程池任务执行前恢复上下文 → 子线程使用副本数据 |
1.ThreadLocal
ThreadLocal 适用于每个线程需要自己独立的实例且该实例需要在多个方法中被使用,即变量在线程间隔离而在方法或类间共享的场景。
原理:每个线程通过 Thread
内部的 ThreadLocalMap
存储数据,键为 ThreadLocal
实例,值为线程私有数据。通过弱引用解决内存泄漏问题,但需手动调用 remove()
清理。
ThreadLocal很多地方叫线程本地变量,ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。也就是对于同一个ThreadLocal,每个线程通过get、set、remove接口操作只会影响自身线程的数据,不会干扰其他线程中的数据。
核心类:
- ThreadLocal 核心类,本地线程类,他里边有两个子类:SuppliedThreadLocal这个主要是传的表达式相当于延迟初始化,当调用get的时候才会获取值;ThreadLocalMap这个就是用来存放数据管理数据的,会依附在 Thread 里;
- Thread 线程类 内部拥有ThreadLocalMap变量,有两个,threadLocals 负责正常存放某个本地线程变量,inheritableThreadLocals负责父子线程传递的;
- InheritableThreadLocal 用于父子线程的传递
2.InheritableThreadLocal
原理:InheritableThreadLocal仅仅是重写了ThreadLocal3个方法。在new Thread的时候,InheritableThreadLocal会将父线程的ThreadLocal设置到子线程中。
在使用线程池的时候:
InheritableThreadLocal和线程池搭配使用时,可能得不到想要的结果,因为线程池中的线程是复用的,并没有重新初始化线程,InheritableThreadLocal之所以起作用是因为在Thread类中最终会调用init()方法去把InheritableThreadLocal的map复制到子线程中。由于线程池复用了已有线程,所以没有调用init()方法这个过程,也就不能将父线程中的InheritableThreadLocal值传给子线程。
3.TransmittableThreadLocal (TTL)
TransmittableThreadLocal是阿里开源的一个类,主要目的是处理父子线程变量不能共用的情况。在使用线程池等会池化复用线程的执行组件情况下,提供ThreadLocal值的传递功能,解决异步执行时上下文传递的问题。
核心源码:在set方法中的addValue中,使用到Holder保存线程的信息,然后copy到其他线程中使用。
TransmittableThreadLocal使用的2种方式
- 使用TtlRunnable get(@Nullable Runnable runnable)装饰Runnable或使用TtlCallable get(@Nullable Callable callable)装饰callable。
- ExecutorService getTtlExecutorService(@Nullable ExecutorService executorService)装饰executorService。
1、何时进行当前线程上下文的获取?
由于上面的场景存在延时执行,那么获取上下文就只能在新线程创建的时候,对于使用其它线程(线程池存在的线程)就只能是创建任务的时候。
2、如何拷贝上下文?
对于引用对象来说,如果直接使用其地址,可能就存在问题,外层会影响到执行线程的信息,这需要根据业务场景来确定,是否能影响。
3、对于当前线程执行的情况,如何保证上下文不丢失?
这种情况出现在,当我们提交的任务被划分的线程有自己的上下文(任务的提交和实际执行中间存在时间差,如果这个时间段出现了上下文的更新,那么直接覆盖将导致本次更新丢失),那么就需要保证在任务执行的时候是当时的上下文,执行完毕后需要还原。
4、什么时候设置上下文?
由于前面我们知道,在任务提交和执行存在一定的时间差,那么设置上下文的时候,就不能是创建的时候,只能是在执行之前(如果在创建的时候,还需要考虑,中途如果没轮到该任务执行就设置了上下文,线程如果还有其它的流程需要执行,就会导致上下文丢失问题)
二、优缺点对比
类别 | 优点 | 缺点 |
---|---|---|
ThreadLocal | 轻量级、线程隔离性强、无锁性能高 | 父子线程无法传递数据、线程池场景失效、内存泄漏风险需手动清理 |
InheritableThreadLocal | 支持父子线程数据传递 | 线程池复用线程时数据丢失、无法跨任务传递 |
TransmittableThreadLocal | 支持线程池上下文传递、兼容异步框架、自动清理副本 | 需显式包装任务(TtlRunnable )、代码侵入性较高 |
三、适用场景总结
- ThreadLocal:单线程数据隔离(如 Spring 的
RequestContextHolder
)。 - InheritableThreadLocal:简单父子线程数据传递(如单次任务拆分)。
- TransmittableThreadLocal:线程池、异步任务、分布式链路跟踪(如日志
traceId
透传)
1.注意事项
-
内存泄漏
ThreadLocal
需在try-finally
块中调用remove()
,避免Entry
中值未释放。- 弱引用问题:若
ThreadLocal
实例被回收,Entry
的键变为null
,但值仍可能泄漏,需结合remove()
使用。
-
线程池场景适配
InheritableThreadLocal
不适用于线程池(线程复用导致数据混乱),需改用TransmittableThreadLocal
。
-
TTL 使用规范
- 任务必须通过
TtlRunnable
或TtlCallable
包装,否则上下文丢失。 - 避免跨线程修改 TTL 值,需保证线程安全。
- 任务必须通过
-
性能影响
ThreadLocal
的get()
/set()
操作基于哈希表,时间复杂度接近 O(1)。- TTL 的上下文捕获和恢复会引入额外性能开销(约 1%~3%)。
2.用法与代码示例
1. ThreadLocal
适用场景:会话管理、数据库连接隔离、请求链路跟踪
ThreadLocal 数据流:
线程 → ThreadLocalMap
→ Entry(ThreadLocal弱引用, 值)
→ 线程私有访问。
// 定义
private static final ThreadLocal<String> context = new ThreadLocal<>();
// 设置值
context.set("user123");
// 获取值
String userId = context.get(); // "user123" 线程隔离、独一份;父子线程间不影响;线程池中的线程间也不共享。
// 清理
context.remove(); // 防止内存泄漏
2. InheritableThreadLocal
适用场景:父子线程数据传递(非线程池场景)
InheritableThreadLocal 数据流:
父线程 → inheritableThreadLocals → 子线程初始化时复制→ ThreadLocalMap
→ Entry(ThreadLocal弱引用, 值)
→ 线程私有访问。
private static final InheritableThreadLocal<String> parentContext = new InheritableThreadLocal<>();
// 父线程设置
parentContext.set("parentData");
// 子线程继承
new Thread(() -> {
System.out.println(parentContext.get()); // "parentData" 从父线程中copy一份
}).start();
3. TransmittableThreadLocal
适用场景:线程池、异步框架(如CompletableFuture)、分布式链路跟踪
TTL 任务执行流程:
主线程设置 TTL → 包装任务(TtlRunnable
)→ 线程池执行前备份主线程数据 → 子线程执行时恢复数据 → 任务完成清理副本。
private static final TransmittableThreadLocal<String> ttlContext = new TransmittableThreadLocal<>();
// 主线程设置
ttlContext.set("taskData");
// 线程池任务包装
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.execute(TtlRunnable.get(() -> {
System.out.println(ttlContext.get()); // "taskData"
}));
4.详细示例
public class _3ThreadLocalTest {
public static void main(String[] args) throws InterruptedException {
ThreadLocalTest(2,5);
InheritableThreadLocal(2,5);
TransmittableThreadLocal(2,5);
ThreadLocalTestWithRemove(2,5);
InheritableThreadLocalWithRemove(2,5);
TransmittableThreadLocalWithRemove(2,5);
/**
* todo
* 父线程的修改
* 1.如果不用线程池,则子线程可以获取到父线程的修改
* 2.如果用线程池,则子线程间会复用,只要不remove;
* 子线程创建的时候,会将父线程的InheritableThreadLocal复制一份到子线程中的InheritableThreadLocal,后续父线程中的修改对子线程不影响。
* (这也是线程池子线程复用的原因,也就是InheritableThreadLocal无法解决主线程和线程池中数据共享的问题)
* 如何解决这个难题?
* 我们可以通过自定义线程池解决,需要重写线程池的execute和submit方法,
* 在线程池执行任务前,先将需要在线程池中共享的数据取出来,然后在执行任务的时候,再将这个数据塞到线程池执行任务的线程中就可以了。
*
*
* 2025-04-16 20:04:24 939 | 1744805064941 | 1 | main | RUNNABLE | ThreadLocalTest : 父线程数据
* 2025-04-16 20:04:24 966 | 1744805064967 | 13 | pool-1-thread-1 | RUNNABLE | ThreadLocalTest 子线程获取数据: :
* 2025-04-16 20:04:24 968 | 1744805064968 | 13 | pool-1-thread-1 | RUNNABLE | ThreadLocalTest 子线程获取数据: :
* 2025-04-16 20:04:24 968 | 1744805064968 | 13 | pool-1-thread-1 | RUNNABLE | ThreadLocalTest 子线程获取数据: :
* 2025-04-16 20:04:24 969 | 1744805064969 | 13 | pool-1-thread-1 | RUNNABLE | ThreadLocalTest 子线程获取数据: :
* 2025-04-16 20:04:24 970 | 1744805064970 | 14 | pool-1-thread-2 | RUNNABLE | ThreadLocalTest 子线程获取数据: :
*
* 2025-04-16 20:04:24 971 | 1744805064971 | 1 | main | RUNNABLE | InheritableThreadLocal : 父线程数据
* 2025-04-16 20:04:24 973 | 1744805064973 | 15 | pool-2-thread-1 | RUNNABLE | InheritableThreadLocal 子线程获取数据: : 父线程数据:0
* 2025-04-16 20:04:24 973 | 1744805064973 | 16 | pool-2-thread-2 | RUNNABLE | InheritableThreadLocal 子线程获取数据: : 父线程数据:1
* 2025-04-16 20:04:24 974 | 1744805064974 | 15 | pool-2-thread-1 | RUNNABLE | InheritableThreadLocal 子线程获取数据: : 父线程数据:0
* 2025-04-16 20:04:24 974 | 1744805064974 | 16 | pool-2-thread-2 | RUNNABLE | InheritableThreadLocal 子线程获取数据: : 父线程数据:1
* 2025-04-16 20:04:24 974 | 1744805064974 | 15 | pool-2-thread-1 | RUNNABLE | InheritableThreadLocal 子线程获取数据: : 父线程数据:0
*
* 2025-04-16 20:04:25 014 | 1744805065015 | 1 | main | RUNNABLE | TransmittableThreadLocal : 父线程数据
* 2025-04-16 20:04:25 025 | 1744805065025 | 18 | pool-3-thread-1 | RUNNABLE | TransmittableThreadLocal 子线程获取数据: : 父线程数据:0
* 2025-04-16 20:04:25 026 | 1744805065026 | 18 | pool-3-thread-1 | RUNNABLE | TransmittableThreadLocal 子线程获取数据: : 父线程数据:0
* 2025-04-16 20:04:25 027 | 1744805065027 | 18 | pool-3-thread-1 | RUNNABLE | TransmittableThreadLocal 子线程获取数据: : 父线程数据:0
* 2025-04-16 20:04:25 028 | 1744805065028 | 18 | pool-3-thread-1 | RUNNABLE | TransmittableThreadLocal 子线程获取数据: : 父线程数据:0
* 2025-04-16 20:04:25 029 | 1744805065030 | 19 | pool-3-thread-2 | RUNNABLE | TransmittableThreadLocal 子线程获取数据: : 父线程数据:1
*
* 2025-04-16 20:04:25 030 | 1744805065030 | 1 | main | RUNNABLE | ThreadLocalTestWithRemove : 父线程数据
* 2025-04-16 20:04:25 033 | 1744805065033 | 20 | pool-4-thread-1 | RUNNABLE | ThreadLocalTestWithRemove 子线程获取数据: :
* 2025-04-16 20:04:25 033 | 1744805065033 | 20 | pool-4-thread-1 | RUNNABLE | ThreadLocalTestWithRemove 子线程获取数据: :
* 2025-04-16 20:04:25 034 | 1744805065034 | 20 | pool-4-thread-1 | RUNNABLE | ThreadLocalTestWithRemove 子线程获取数据: :
* 2025-04-16 20:04:25 034 | 1744805065034 | 20 | pool-4-thread-1 | RUNNABLE | ThreadLocalTestWithRemove 子线程获取数据: :
* 2025-04-16 20:04:25 035 | 1744805065035 | 21 | pool-4-thread-2 | RUNNABLE | ThreadLocalTestWithRemove 子线程获取数据: :
*
* 2025-04-16 20:04:25 035 | 1744805065035 | 1 | main | RUNNABLE | InheritableThreadLocalWithRemove : 父线程数据
* 2025-04-16 20:04:25 038 | 1744805065038 | 23 | pool-5-thread-2 | RUNNABLE | InheritableThreadLocalWithRemove 子线程获取数据: : 父线程数据:1
* 2025-04-16 20:04:25 038 | 1744805065038 | 22 | pool-5-thread-1 | RUNNABLE | InheritableThreadLocalWithRemove 子线程获取数据: : 父线程数据:0
* 2025-04-16 20:04:25 038 | 1744805065038 | 22 | pool-5-thread-1 | RUNNABLE | InheritableThreadLocalWithRemove 子线程获取数据: :
* 2025-04-16 20:04:25 038 | 1744805065038 | 23 | pool-5-thread-2 | RUNNABLE | InheritableThreadLocalWithRemove 子线程获取数据: :
* 2025-04-16 20:04:25 038 | 1744805065038 | 22 | pool-5-thread-1 | RUNNABLE | InheritableThreadLocalWithRemove 子线程获取数据: :
*
* 2025-04-16 20:04:25 039 | 1744805065039 | 1 | main | RUNNABLE | TransmittableThreadLocalWithRemove : 父线程数据
* 2025-04-16 20:04:25 044 | 1744805065044 | 25 | pool-6-thread-2 | RUNNABLE | TransmittableThreadLocalWithRemove 子线程获取数据: : 父线程数据:1
* 2025-04-16 20:04:25 045 | 1744805065045 | 25 | pool-6-thread-2 | RUNNABLE | TransmittableThreadLocalWithRemove 子线程获取数据: :
* 2025-04-16 20:04:25 045 | 1744805065045 | 25 | pool-6-thread-2 | RUNNABLE | TransmittableThreadLocalWithRemove 子线程获取数据: :
* 2025-04-16 20:04:25 045 | 1744805065046 | 25 | pool-6-thread-2 | RUNNABLE | TransmittableThreadLocalWithRemove 子线程获取数据: :
* 2025-04-16 20:04:25 044 | 1744805065044 | 24 | pool-6-thread-1 | RUNNABLE | TransmittableThreadLocalWithRemove 子线程获取数据: : 父线程数据:0
*
* */
ThreadLocalTest(5,5);
InheritableThreadLocal(5,5);
TransmittableThreadLocal(5,5);
ThreadLocalTestWithRemove(5,5);
InheritableThreadLocalWithRemove(5,5);
TransmittableThreadLocalWithRemove(5,5);
/**
* 2025-04-16 20:11:15 876 | 1744805475876 | 1 | main | RUNNABLE | ThreadLocalTest : 父线程数据
* 2025-04-16 20:11:15 882 | 1744805475882 | 26 | pool-7-thread-1 | RUNNABLE | ThreadLocalTest 子线程获取数据: :
* 2025-04-16 20:11:15 883 | 1744805475883 | 30 | pool-7-thread-5 | RUNNABLE | ThreadLocalTest 子线程获取数据: :
* 2025-04-16 20:11:15 883 | 1744805475883 | 28 | pool-7-thread-3 | RUNNABLE | ThreadLocalTest 子线程获取数据: :
* 2025-04-16 20:11:15 883 | 1744805475883 | 29 | pool-7-thread-4 | RUNNABLE | ThreadLocalTest 子线程获取数据: :
* 2025-04-16 20:11:15 883 | 1744805475883 | 27 | pool-7-thread-2 | RUNNABLE | ThreadLocalTest 子线程获取数据: :
* 2025-04-16 20:11:15 885 | 1744805475885 | 1 | main | RUNNABLE | InheritableThreadLocal : 父线程数据
* 2025-04-16 20:11:15 890 | 1744805475890 | 31 | pool-8-thread-1 | RUNNABLE | InheritableThreadLocal 子线程获取数据: : 父线程数据:0
* 2025-04-16 20:11:15 892 | 1744805475892 | 35 | pool-8-thread-5 | RUNNABLE | InheritableThreadLocal 子线程获取数据: : 父线程数据:4
* 2025-04-16 20:11:15 892 | 1744805475892 | 33 | pool-8-thread-3 | RUNNABLE | InheritableThreadLocal 子线程获取数据: : 父线程数据:2
* 2025-04-16 20:11:15 892 | 1744805475892 | 32 | pool-8-thread-2 | RUNNABLE | InheritableThreadLocal 子线程获取数据: : 父线程数据:1
* 2025-04-16 20:11:15 892 | 1744805475892 | 34 | pool-8-thread-4 | RUNNABLE | InheritableThreadLocal 子线程获取数据: : 父线程数据:3
* 2025-04-16 20:11:15 894 | 1744805475894 | 1 | main | RUNNABLE | TransmittableThreadLocal : 父线程数据
* 2025-04-16 20:11:15 924 | 1744805475924 | 36 | pool-9-thread-1 | RUNNABLE | TransmittableThreadLocal 子线程获取数据: : 父线程数据:0
* 2025-04-16 20:11:15 924 | 1744805475925 | 39 | pool-9-thread-4 | RUNNABLE | TransmittableThreadLocal 子线程获取数据: : 父线程数据:3
* 2025-04-16 20:11:15 925 | 1744805475925 | 38 | pool-9-thread-3 | RUNNABLE | TransmittableThreadLocal 子线程获取数据: : 父线程数据:2
* 2025-04-16 20:11:15 925 | 1744805475925 | 37 | pool-9-thread-2 | RUNNABLE | TransmittableThreadLocal 子线程获取数据: : 父线程数据:1
* 2025-04-16 20:11:15 924 | 1744805475925 | 40 | pool-9-thread-5 | RUNNABLE | TransmittableThreadLocal 子线程获取数据: : 父线程数据:4
* 2025-04-16 20:11:15 926 | 1744805475926 | 1 | main | RUNNABLE | ThreadLocalTestWithRemove : 父线程数据
* 2025-04-16 20:11:15 932 | 1744805475932 | 41 | pool-10-thread-1 | RUNNABLE | ThreadLocalTestWithRemove 子线程获取数据: :
* 2025-04-16 20:11:15 934 | 1744805475934 | 45 | pool-10-thread-5 | RUNNABLE | ThreadLocalTestWithRemove 子线程获取数据: :
* 2025-04-16 20:11:15 934 | 1744805475934 | 44 | pool-10-thread-4 | RUNNABLE | ThreadLocalTestWithRemove 子线程获取数据: :
* 2025-04-16 20:11:15 935 | 1744805475935 | 43 | pool-10-thread-3 | RUNNABLE | ThreadLocalTestWithRemove 子线程获取数据: :
* 2025-04-16 20:11:15 935 | 1744805475935 | 42 | pool-10-thread-2 | RUNNABLE | ThreadLocalTestWithRemove 子线程获取数据: :
* 2025-04-16 20:11:15 936 | 1744805475936 | 1 | main | RUNNABLE | InheritableThreadLocalWithRemove : 父线程数据
* 2025-04-16 20:11:15 938 | 1744805475938 | 46 | pool-11-thread-1 | RUNNABLE | InheritableThreadLocalWithRemove 子线程获取数据: : 父线程数据:0
* 2025-04-16 20:11:15 939 | 1744805475939 | 49 | pool-11-thread-4 | RUNNABLE | InheritableThreadLocalWithRemove 子线程获取数据: : 父线程数据:3
* 2025-04-16 20:11:15 939 | 1744805475939 | 47 | pool-11-thread-2 | RUNNABLE | InheritableThreadLocalWithRemove 子线程获取数据: : 父线程数据:1
* 2025-04-16 20:11:15 939 | 1744805475939 | 50 | pool-11-thread-5 | RUNNABLE | InheritableThreadLocalWithRemove 子线程获取数据: : 父线程数据:4
* 2025-04-16 20:11:15 940 | 1744805475940 | 48 | pool-11-thread-3 | RUNNABLE | InheritableThreadLocalWithRemove 子线程获取数据: : 父线程数据:2
* 2025-04-16 20:11:15 941 | 1744805475941 | 1 | main | RUNNABLE | TransmittableThreadLocalWithRemove : 父线程数据
* 2025-04-16 20:11:15 961 | 1744805475962 | 51 | pool-12-thread-1 | RUNNABLE | TransmittableThreadLocalWithRemove 子线程获取数据: : 父线程数据:0
* 2025-04-16 20:11:15 963 | 1744805475963 | 55 | pool-12-thread-5 | RUNNABLE | TransmittableThreadLocalWithRemove 子线程获取数据: : 父线程数据:4
* 2025-04-16 20:11:15 963 | 1744805475963 | 53 | pool-12-thread-3 | RUNNABLE | TransmittableThreadLocalWithRemove 子线程获取数据: : 父线程数据:2
* 2025-04-16 20:11:15 963 | 1744805475963 | 52 | pool-12-thread-2 | RUNNABLE | TransmittableThreadLocalWithRemove 子线程获取数据: : 父线程数据:1
* 2025-04-16 20:11:15 963 | 1744805475963 | 54 | pool-12-thread-4 | RUNNABLE | TransmittableThreadLocalWithRemove 子线程获取数据: : 父线程数据:3
*
* */
TransmittableThreadLocal2(2,5);
TransmittableThreadLocalWithRemove2(5,5);
/**
* 子线程创建的时候,会将父线程的InheritableThreadLocal复制一份到子线程中的InheritableThreadLocal,后续父线程中的修改对子线程不影响。
* (这也是线程池子线程复用的原因,也就是InheritableThreadLocal无法解决主线程和线程池中数据共享的问题)
*
* ExecutorService executorService= TtlExecutors.getTtlExecutorService( Executors.newFixedThreadPool(poolSize));
* todo 可以看到加了TtlExecutors.getTtlExecutorService这个才会解决线程池中数据共享的问题
*
* 2025-04-16 20:22:02 537 | 1744806122537 | 1 | main | RUNNABLE | TransmittableThreadLocal : 父线程数据
* 2025-04-16 20:22:02 561 | 1744806122561 | 56 | pool-13-thread-1 | RUNNABLE | TransmittableThreadLocal 子线程获取数据: : 父线程数据:0
* 2025-04-16 20:22:02 561 | 1744806122561 | 57 | pool-13-thread-2 | RUNNABLE | TransmittableThreadLocal 子线程获取数据: : 父线程数据:1
* 2025-04-16 20:22:02 561 | 1744806122562 | 57 | pool-13-thread-2 | RUNNABLE | TransmittableThreadLocal 子线程获取数据: : 父线程数据:2
* 2025-04-16 20:22:02 561 | 1744806122562 | 56 | pool-13-thread-1 | RUNNABLE | TransmittableThreadLocal 子线程获取数据: : 父线程数据:3
* 2025-04-16 20:22:02 562 | 1744806122562 | 57 | pool-13-thread-2 | RUNNABLE | TransmittableThreadLocal 子线程获取数据: : 父线程数据:4
*
* 2025-04-16 20:22:02 562 | 1744806122562 | 1 | main | RUNNABLE | TransmittableThreadLocalWithRemove : 父线程数据
* 2025-04-16 20:22:02 566 | 1744806122566 | 58 | pool-14-thread-1 | RUNNABLE | TransmittableThreadLocalWithRemove 子线程获取数据: : 父线程数据:0
* 2025-04-16 20:22:02 567 | 1744806122568 | 60 | pool-14-thread-3 | RUNNABLE | TransmittableThreadLocalWithRemove 子线程获取数据: : 父线程数据:2
* 2025-04-16 20:22:02 568 | 1744806122568 | 59 | pool-14-thread-2 | RUNNABLE | TransmittableThreadLocalWithRemove 子线程获取数据: : 父线程数据:1
* 2025-04-16 20:22:02 569 | 1744806122569 | 61 | pool-14-thread-4 | RUNNABLE | TransmittableThreadLocalWithRemove 子线程获取数据: : 父线程数据:3
* 2025-04-16 20:22:02 571 | 1744806122571 | 62 | pool-14-thread-5 | RUNNABLE | TransmittableThreadLocalWithRemove 子线程获取数据: : 父线程数据:4
*
*
* */
ThreadLocalTest4ThreadPoolExecutor4ThreadLocal(2,5);
ThreadLocalTestWithRemove4ThreadPoolExecutor4ThreadLocal(2,5);
ThreadLocalTest4ThreadPoolExecutor4ThreadLocal(5,5);
ThreadLocalTestWithRemove4ThreadPoolExecutor4ThreadLocal(5,5);
ThreadLocalTest4ThreadPoolExecutor4ThreadLocal(5,2);
ThreadLocalTestWithRemove4ThreadPoolExecutor4ThreadLocal(5,2);
/**
* (这也是线程池子线程复用的原因,也就是InheritableThreadLocal无法解决主线程和线程池中数据共享的问题)
* 如何解决这个问题?
* 我们可以通过自定义线程池解决,需要重写线程池的execute和submit方法,
* 在线程池执行任务前,先将需要在线程池中共享的数据取出来,然后在执行任务的时候,再将这个数据塞到线程池执行任务的线程中就可以。
*
* 2025-04-16 20:59:08 116 | 1744808348116 | 1 | main | RUNNABLE | ThreadLocalTest : 父线程数据
* 2025-04-16 20:59:08 123 | 1744808348123 | 63 | pool-15-thread-1 | RUNNABLE | ThreadLocalTest 子线程获取数据: : 父线程数据:0
* 2025-04-16 20:59:08 123 | 1744808348123 | 64 | pool-15-thread-2 | RUNNABLE | ThreadLocalTest 子线程获取数据: : 父线程数据:1
* 2025-04-16 20:59:08 123 | 1744808348123 | 64 | pool-15-thread-2 | RUNNABLE | ThreadLocalTest 子线程获取数据: : 父线程数据:2
* 2025-04-16 20:59:08 123 | 1744808348123 | 63 | pool-15-thread-1 | RUNNABLE | ThreadLocalTest 子线程获取数据: : 父线程数据:3
* 2025-04-16 20:59:08 123 | 1744808348123 | 64 | pool-15-thread-2 | RUNNABLE | ThreadLocalTest 子线程获取数据: : 父线程数据:4
* 2025-04-16 20:59:08 124 | 1744808348124 | 1 | main | RUNNABLE | ThreadLocalTestWithRemove : 父线程数据
* 2025-04-16 20:59:08 129 | 1744808348129 | 65 | pool-16-thread-1 | RUNNABLE | ThreadLocalTestWithRemove 子线程获取数据: : 父线程数据:0
* 2025-04-16 20:59:08 129 | 1744808348130 | 65 | pool-16-thread-1 | RUNNABLE | ThreadLocalTestWithRemove 子线程获取数据: : 父线程数据:2
* 2025-04-16 20:59:08 130 | 1744808348130 | 65 | pool-16-thread-1 | RUNNABLE | ThreadLocalTestWithRemove 子线程获取数据: : 父线程数据:3
* 2025-04-16 20:59:08 130 | 1744808348130 | 66 | pool-16-thread-2 | RUNNABLE | ThreadLocalTestWithRemove 子线程获取数据: : 父线程数据:1
* 2025-04-16 20:59:08 130 | 1744808348130 | 65 | pool-16-thread-1 | RUNNABLE | ThreadLocalTestWithRemove 子线程获取数据: : 父线程数据:4
* 2025-04-16 20:59:08 130 | 1744808348130 | 1 | main | RUNNABLE | ThreadLocalTest : 父线程数据
* 2025-04-16 20:59:08 132 | 1744808348132 | 67 | pool-17-thread-1 | RUNNABLE | ThreadLocalTest 子线程获取数据: : 父线程数据:0
* 2025-04-16 20:59:08 132 | 1744808348132 | 68 | pool-17-thread-2 | RUNNABLE | ThreadLocalTest 子线程获取数据: : 父线程数据:1
* 2025-04-16 20:59:08 134 | 1744808348134 | 69 | pool-17-thread-3 | RUNNABLE | ThreadLocalTest 子线程获取数据: : 父线程数据:2
* 2025-04-16 20:59:08 135 | 1744808348136 | 70 | pool-17-thread-4 | RUNNABLE | ThreadLocalTest 子线程获取数据: : 父线程数据:3
* 2025-04-16 20:59:08 135 | 1744808348136 | 71 | pool-17-thread-5 | RUNNABLE | ThreadLocalTest 子线程获取数据: : 父线程数据:4
* 2025-04-16 20:59:08 136 | 1744808348136 | 1 | main | RUNNABLE | ThreadLocalTestWithRemove : 父线程数据
* 2025-04-16 20:59:08 138 | 1744808348138 | 73 | pool-18-thread-2 | RUNNABLE | ThreadLocalTestWithRemove 子线程获取数据: : 父线程数据:1
* 2025-04-16 20:59:08 138 | 1744808348138 | 72 | pool-18-thread-1 | RUNNABLE | ThreadLocalTestWithRemove 子线程获取数据: : 父线程数据:0
* 2025-04-16 20:59:08 139 | 1744808348139 | 74 | pool-18-thread-3 | RUNNABLE | ThreadLocalTestWithRemove 子线程获取数据: : 父线程数据:2
* 2025-04-16 20:59:08 139 | 1744808348139 | 75 | pool-18-thread-4 | RUNNABLE | ThreadLocalTestWithRemove 子线程获取数据: : 父线程数据:3
* 2025-04-16 20:59:08 139 | 1744808348139 | 76 | pool-18-thread-5 | RUNNABLE | ThreadLocalTestWithRemove 子线程获取数据: : 父线程数据:4
* 2025-04-16 20:59:08 140 | 1744808348140 | 1 | main | RUNNABLE | ThreadLocalTest : 父线程数据
* 2025-04-16 20:59:08 141 | 1744808348141 | 77 | pool-19-thread-1 | RUNNABLE | ThreadLocalTest 子线程获取数据: : 父线程数据:0
* 2025-04-16 20:59:08 141 | 1744808348141 | 78 | pool-19-thread-2 | RUNNABLE | ThreadLocalTest 子线程获取数据: : 父线程数据:1
* 2025-04-16 20:59:08 142 | 1744808348142 | 1 | main | RUNNABLE | ThreadLocalTestWithRemove : 父线程数据
* 2025-04-16 20:59:08 143 | 1744808348143 | 79 | pool-20-thread-1 | RUNNABLE | ThreadLocalTestWithRemove 子线程获取数据: : 父线程数据:0
* 2025-04-16 20:59:08 144 | 1744808348144 | 80 | pool-20-thread-2 | RUNNABLE | ThreadLocalTestWithRemove 子线程获取数据: : 父线程数据:1
*
* */
}
public static void ThreadLocalTest(int poolSize,int thread) throws InterruptedException {
ThreadLocal<String> threadLocal=new ThreadLocal<>();
threadLocal.set("父线程数据");
ZhouxxTool.printTimeAndThread("ThreadLocalTest ",threadLocal.get());
ExecutorService executorService= Executors.newFixedThreadPool(poolSize);
for(int i=0;i<thread;i++){
threadLocal.set("父线程数据:"+i);
executorService.execute(()->{
ZhouxxTool.printTimeAndThread("ThreadLocalTest 子线程获取数据:",threadLocal.get());
});
}
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.MINUTES);
}
public static void InheritableThreadLocal(int poolSize,int thread) throws InterruptedException {
InheritableThreadLocal<String> threadLocal=new InheritableThreadLocal<>();
threadLocal.set("父线程数据");
ZhouxxTool.printTimeAndThread("InheritableThreadLocal ",threadLocal.get());
ExecutorService executorService= Executors.newFixedThreadPool(poolSize);
for(int i=0;i<thread;i++){
threadLocal.set("父线程数据:"+i);
executorService.execute(()->{
ZhouxxTool.printTimeAndThread("InheritableThreadLocal 子线程获取数据:",threadLocal.get());
});
}
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.MINUTES);
}
public static void TransmittableThreadLocal(int poolSize,int thread) throws InterruptedException {
TransmittableThreadLocal<String> threadLocal=new TransmittableThreadLocal<>();
threadLocal.set("父线程数据");
ZhouxxTool.printTimeAndThread("TransmittableThreadLocal ",threadLocal.get());
ExecutorService executorService= Executors.newFixedThreadPool(poolSize);
for(int i=0;i<thread;i++){
threadLocal.set("父线程数据:"+i);
executorService.execute(()->{
ZhouxxTool.printTimeAndThread("TransmittableThreadLocal 子线程获取数据:",threadLocal.get());
});
}
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.MINUTES);
}
public static void TransmittableThreadLocal2(int poolSize,int thread) throws InterruptedException {
TransmittableThreadLocal<String> threadLocal=new TransmittableThreadLocal<>();
threadLocal.set("父线程数据");
ZhouxxTool.printTimeAndThread("TransmittableThreadLocal ",threadLocal.get());
//ExecutorService executorService= Executors.newFixedThreadPool(poolSize);
ExecutorService executorService= TtlExecutors.getTtlExecutorService( Executors.newFixedThreadPool(poolSize));
for(int i=0;i<thread;i++){
threadLocal.set("父线程数据:"+i);
executorService.execute(()->{
ZhouxxTool.printTimeAndThread("TransmittableThreadLocal 子线程获取数据:",threadLocal.get());
});
}
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.MINUTES);
}
public static void ThreadLocalTestWithRemove(int poolSize,int thread) throws InterruptedException {
ThreadLocal<String> threadLocal=new ThreadLocal<>();
threadLocal.set("父线程数据");
ZhouxxTool.printTimeAndThread("ThreadLocalTestWithRemove ",threadLocal.get());
ExecutorService executorService= Executors.newFixedThreadPool(poolSize);
for(int i=0;i<thread;i++){
threadLocal.set("父线程数据:"+i);
executorService.execute(()->{
ZhouxxTool.printTimeAndThread("ThreadLocalTestWithRemove 子线程获取数据:",threadLocal.get());
threadLocal.remove();
});
}
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.MINUTES);
}
public static void InheritableThreadLocalWithRemove(int poolSize,int thread) throws InterruptedException {
InheritableThreadLocal<String> threadLocal=new InheritableThreadLocal<>();
threadLocal.set("父线程数据");
ZhouxxTool.printTimeAndThread("InheritableThreadLocalWithRemove ",threadLocal.get());
ExecutorService executorService= Executors.newFixedThreadPool(poolSize);
for(int i=0;i<thread;i++){
threadLocal.set("父线程数据:"+i);
executorService.execute(()->{
ZhouxxTool.printTimeAndThread("InheritableThreadLocalWithRemove 子线程获取数据:",threadLocal.get());
threadLocal.remove();
});
}
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.MINUTES);
}
public static void TransmittableThreadLocalWithRemove(int poolSize,int thread) throws InterruptedException {
TransmittableThreadLocal<String> threadLocal=new TransmittableThreadLocal<>();
threadLocal.set("父线程数据");
ZhouxxTool.printTimeAndThread("TransmittableThreadLocalWithRemove ",threadLocal.get());
ExecutorService executorService= Executors.newFixedThreadPool(poolSize);
for(int i=0;i<thread;i++){
threadLocal.set("父线程数据:"+i);
executorService.execute(()->{
ZhouxxTool.printTimeAndThread("TransmittableThreadLocalWithRemove 子线程获取数据:",threadLocal.get());
threadLocal.remove();
});
}
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.MINUTES);
}
public static void TransmittableThreadLocalWithRemove2(int poolSize,int thread) throws InterruptedException {
TransmittableThreadLocal<String> threadLocal=new TransmittableThreadLocal<>();
threadLocal.set("父线程数据");
ZhouxxTool.printTimeAndThread("TransmittableThreadLocalWithRemove ",threadLocal.get());
//ExecutorService executorService= Executors.newFixedThreadPool(poolSize);
ExecutorService executorService= TtlExecutors.getTtlExecutorService( Executors.newFixedThreadPool(poolSize));
for(int i=0;i<thread;i++){
threadLocal.set("父线程数据:"+i);
executorService.execute(()->{
ZhouxxTool.printTimeAndThread("TransmittableThreadLocalWithRemove 子线程获取数据:",threadLocal.get());
threadLocal.remove();
});
}
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.MINUTES);
}
public static void ThreadLocalTest4ThreadPoolExecutor4ThreadLocal(int poolSize,int thread) throws InterruptedException {
//InheritableThreadLocal<String> threadLocal=new InheritableThreadLocal<>();
ThreadPoolExecutor4ThreadLocal.getContextHolder().set("父线程数据");
ZhouxxTool.printTimeAndThread("ThreadLocalTest ",ThreadPoolExecutor4ThreadLocal.getContextHolder().get());
//ExecutorService executorService= Executors.newFixedThreadPool(poolSize);
ThreadPoolExecutor4ThreadLocal executorService = new ThreadPoolExecutor4ThreadLocal(
poolSize, poolSize, 30, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100),
Executors.defaultThreadFactory()
);
for(int i=0;i<thread;i++){
ThreadPoolExecutor4ThreadLocal.getContextHolder().set("父线程数据:"+i);
executorService.execute(()->{
ZhouxxTool.printTimeAndThread("ThreadLocalTest 子线程获取数据:",ThreadPoolExecutor4ThreadLocal.getContextHolder().get());
});
}
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.MINUTES);
}
public static void ThreadLocalTestWithRemove4ThreadPoolExecutor4ThreadLocal(int poolSize,int thread) throws InterruptedException {
//InheritableThreadLocal<String> threadLocal=new InheritableThreadLocal<>();
ThreadPoolExecutor4ThreadLocal.getContextHolder().set("父线程数据");
ZhouxxTool.printTimeAndThread("ThreadLocalTestWithRemove ", ThreadPoolExecutor4ThreadLocal.getContextHolder().get());
//ExecutorService executorService= Executors.newFixedThreadPool(poolSize);
ThreadPoolExecutor4ThreadLocal executorService = new ThreadPoolExecutor4ThreadLocal(
poolSize, poolSize, 30, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100),
Executors.defaultThreadFactory()
);
for(int i=0;i<thread;i++){
ThreadPoolExecutor4ThreadLocal.getContextHolder().set("父线程数据:"+i);
executorService.execute(()->{
ZhouxxTool.printTimeAndThread("ThreadLocalTestWithRemove 子线程获取数据:", ThreadPoolExecutor4ThreadLocal.getContextHolder().get());
ThreadPoolExecutor4ThreadLocal.getContextHolder().remove();
});
}
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.MINUTES);
}
}