ThreadLocal / InheritableThreadLocal / TransmittableThreadLocal(TTL)学习总结

ThreadLocal / InheritableThreadLocal / TransmittableThreadLocal(TTL)学习总结

一、ThreadLocal 是什么

一句话定义

ThreadLocal 是一种 线程私有变量机制,用于在同一线程内共享数据,而不同线程之间数据完全隔离。

核心特性

  • 同一个 ThreadLocal,在不同线程中有不同的值
  • 不依赖锁实现线程安全
  • 本质不是"共享",而是"隔离"

数据存储位置(关键)

复制代码
Thread
 └─ ThreadLocalMap
     ├─ key: ThreadLocal(弱引用)
     └─ value: 实际数据(强引用)

ThreadLocal 本身不存数据,数据存在线程内部


二、ThreadLocal 的正确使用方式

基本用法

java 复制代码
ThreadLocal<User> tl = new ThreadLocal<>();

try {
    tl.set(user);
    // 业务逻辑
} finally {
    tl.remove();
}

工程铁律(必须遵守)

  1. ThreadLocal 用完必须 remove
  2. 在线程池 / Web / RPC / MQ 环境中尤其重要
  3. value 不应是大对象或长期对象

为什么会内存泄漏

  • 线程池中的线程不会结束
  • ThreadLocalMap 的 key 是弱引用,会被 GC
  • value 是强引用,会一直挂在线程上

泄漏的不是 ThreadLocal,而是 value


三、InheritableThreadLocal 是什么

定义

InheritableThreadLocal 是 ThreadLocal 的一个变体,允许 子线程继承父线程中的值

继承发生的时机(非常重要)

  • 仅在 new Thread() 时发生
  • 不是 set 时
  • 不是 get 时
  • 与线程池无关

示例

java 复制代码
InheritableThreadLocal<String> itl = new InheritableThreadLocal<>();
itl.set("A");

new Thread(() -> {
    System.out.println(itl.get()); // 输出 A
}).start();

为什么它很危险

  • 线程池中的线程不是新建线程

  • 不会触发继承逻辑

  • 极易造成:

    • 上下文串请求
    • 串用户
    • 串 traceId

工程结论

业务代码中几乎不应该使用 InheritableThreadLocal


四、TransmittableThreadLocal(TTL)是什么

背景问题

  • ThreadLocal:线程池中无法传递上下文
  • InheritableThreadLocal:线程池中行为错误

TTL 的一句话定义

TTL 在提交任务时捕获当前线程的 ThreadLocal 上下文,并在任务执行前后自动传递和恢复

关键特性

  • 对线程池友好
  • 提交任务时传递上下文
  • 执行结束后自动清理

五、TTL 的标准使用方式(生产级)

1️⃣ 定义 TTL

java 复制代码
TransmittableThreadLocal<String> TRACE_ID =
        new TransmittableThreadLocal<>();

2️⃣ 设置和清理(请求入口)

java 复制代码
try {
    TRACE_ID.set(traceId);
    // 同步 + 异步逻辑
} finally {
    TRACE_ID.remove();
}

3️⃣ 包装线程池(关键步骤)

java 复制代码
ExecutorService executor =
    TtlExecutors.getTtlExecutorService(
        Executors.newFixedThreadPool(8)
    );

不包装线程池,TTL 不生效

4️⃣ 提交任务

java 复制代码
executor.submit(() -> {
    log.info("traceId={}", TRACE_ID.get());
});

六、三者对比总结

特性 ThreadLocal InheritableThreadLocal TTL
线程隔离
new Thread 继承
线程池传递
自动清理
生产推荐

七、工程级"无脑规则"

  1. ThreadLocal:用完必 remove
  2. 业务代码避免 InheritableThreadLocal
  3. 跨线程池传上下文:只用 TTL 或框架方案

八、典型使用场景

  • 日志 MDC(traceId)
  • 用户 / 租户上下文
  • RPC 调用链路信息
  • 请求级缓存

九、一句话总复盘

  • ThreadLocal:线程内隔离
  • InheritableThreadLocal:仅适合 new Thread
  • TTL:线程池场景的正确解法

只要涉及线程池 + 上下文传递,TTL 是唯一安全选择

相关推荐
一直不明飞行3 分钟前
Java的equals(),hashCode()应该在什么时候重写
java·开发语言·jvm
原来是猿7 分钟前
腾讯云服务器端口开放完全指南
服务器·网络·腾讯云
REDcker10 分钟前
有限状态机与状态模式详解 FSM建模Java状态模式与C++表驱动模板实践
java·c++·状态模式
盲敲代码的阿豪27 分钟前
Python 入门基础教程(爬虫前置版)
开发语言·爬虫·python
你的保护色39 分钟前
【无标题】
java·服务器·网络
basketball6161 小时前
C++ 构造函数完全指南:从入门到进阶
java·开发语言·c++
楼兰公子1 小时前
RK3588 + Linux7.0.3 网络工程调试错误速查手册
linux·网络·3588
互联科技报1 小时前
2026超融合选型:Top5品牌与市场格局解读
开发语言·perl
IpdataCloud1 小时前
稳定的企业级IP数据接口怎么选?可用性指标+离线库高可用方案
运维·网络·tcp/ip
HMS工业网络1 小时前
如何解决使用TwinCAT时EtherCAT网络出现“Sync Manager Watchdog”报错
网络·网络协议·网络安全