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 是唯一安全选择

相关推荐
小毅&Nora18 小时前
【Java线程安全实战】⑤ 原子类(Atomic)深度解析:无锁编程(Lock-Free)的终极奥义(增强版)
java·多线程·原子操作
深盾科技18 小时前
C++ 中 std::error_code 的应用与实践
java·前端·c++
多米Domi01118 小时前
0x3f 第20天 三更24-32 hot100子串
java·python·算法·leetcode·动态规划
古城小栈18 小时前
rust 中的 结构体 & 枚举
开发语言·rust
人道领域18 小时前
【零基础学java】(不可变集合)
java
阿拉伯柠檬18 小时前
传输层协议TCP(二)
linux·服务器·网络·网络协议·tcp/ip·面试
能量鸣新18 小时前
资源分享第三天
c语言·开发语言·c++·python·计算机视觉·c#
独自归家的兔18 小时前
基于 Doubao-Seedream-4.5 的单张图片生成后端接口实战
java·人工智能·spring boot·后端
Morwit18 小时前
Qt CMake 项目中 QML 和资源文件的引入方式
开发语言·c++·qt