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

相关推荐
怒放吧德德5 小时前
Netty 4.2 入门指南:从概念到第一个程序
java·后端·netty
雨中飘荡的记忆6 小时前
大流量下库存扣减的数据库瓶颈:Redis分片缓存解决方案
java·redis·后端
心之语歌9 小时前
基于注解+拦截器的API动态路由实现方案
java·后端
华仔啊10 小时前
Stream 代码越写越难看?JDFrame 让 Java 逻辑回归优雅
java·后端
ray_liang10 小时前
用六边形架构与整洁架构对比是伪命题?
java·架构
Ray Liang11 小时前
用六边形架构与整洁架构对比是伪命题?
java·python·c#·架构设计
Java水解11 小时前
Java 中间件:Dubbo 服务降级(Mock 机制)
java·后端
SimonKing16 小时前
OpenCode AI辅助编程,不一样的编程思路,不写一行代码
java·后端·程序员
FastBean16 小时前
Jackson View Extension Spring Boot Starter
java·后端
Seven9717 小时前
剑指offer-79、最⻓不含重复字符的⼦字符串
java