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

相关推荐
aq55356008 小时前
三大编程语言深度对比:C# vs 易语言 vs 汇编
开发语言·汇编·c#
头铁的伦8 小时前
QNX 网络模型
linux·网络·车载系统
小贾要学习8 小时前
【Linux】TCP网络通信编程
linux·服务器·网络·c++·网络协议·tcp/ip
独特的螺狮粉8 小时前
云隙一言:鸿蒙Flutter框架 实现的随机名言应用
开发语言·flutter·华为·架构·开源·harmonyos
vortex58 小时前
构建可审计、可分层、可扩展的SSH身份管理体系
网络·ssh·php
光泽雨8 小时前
c# 文件编译的过程
开发语言·c#
极创信息8 小时前
信创系统认证服务怎么做?从适配到验收全流程指南
java·大数据·运维·tomcat·健康医疗
格鸰爱童话8 小时前
向AI学习项目技能(六)
java·人工智能·spring boot·python·学习
赤水无泪8 小时前
09 C++ 11 新增的标准
开发语言
白宇横流学长9 小时前
停车场管理系统的设计与实现
java