990 字
约 3 分钟
7
S05-B04 · ThreadLocal:结构、场景与泄漏
2024-12-31
2026-11-07

适用读者:用过 ThreadLocal 但被"内存泄漏"警告吓到的人。
前置:S05-B01、S04-J01(WeakReference 相关)。
覆盖旧文:A-1117(508) A-1611(184) + 932(65) 933(63) 935(68) 934(59) = 947 点。
覆盖扩展:E-S05-006(弱引用与 Entry 泄漏)。
上一篇:S05-B03 · synchronized 与锁升级
下一篇:S05-B05 · 线程池。


1. 一句话结论

ThreadLocal 不是"线程的本地变量",而是"以线程为 key 的一张表"——表挂在 Thread 上(ThreadLocalMap),ThreadLocal 自己只是 key。

Thread ──► threadLocals: ThreadLocalMap
                └── Entry[weak ref → ThreadLocal] ──► value(强引用)

2. 结构:为什么 key 是弱引用(E-S05-006)

引用 指向 类型
Thread → ThreadLocalMap 表 强引用
Entry.key ThreadLocal 对象 弱引用
Entry.value 业务值 强引用

设计意图:如果 ThreadLocal 对象不再被外部引用,弱引用会被 GC 回收 → key 变 null → 这是"防止 ThreadLocal 本身泄漏"的设计。

但 value 仍然是强引用:如果线程(尤其线程池里的长生命周期线程)不结束,Entry 不会被清理 → value 泄漏。

场景 是否泄漏
线程用完即销毁(new Thread) 随线程结束释放,影响小
线程池复用线程 泄漏(value 一直挂在池线程上)

3. 正确用法三条

规则 原因
用完必须 remove() 清掉 value,避免池线程持有
用 try/finally 包住 保证异常时也清理
不要存大对象 泄漏放大
try {
    ctx.set(user);
    // 业务
} finally {
    ctx.remove();     // ← 关键
}

框架层已在做:Spring 的 RequestContextHolder、事务上下文、日志 MDC 都在 finally 里 remove——它们不泄漏,是因为框架帮你清了。


4. 使用场景(A-934)

场景 为什么合适
请求上下文(用户/租户 ID) 避免层层传参
事务/连接绑定 同线程共享同一连接
日志 MDC 日志自动带上 traceId
非线程安全对象的"每线程实例" SimpleDateFormat(旧写法)

反例:不要用 ThreadLocal 做"全局缓存"——它不是缓存,生命周期绑在线程上。


5. ThreadLocalMap 与 HashMap 的区别(A-935)

维度 ThreadLocalMap HashMap
冲突处理 开放寻址(线性探测) 链地址
key 弱引用 强引用
容量 固定 16 起,2 的幂 同
是否对外 私有 公开

为什么用开放寻址:Entry 数量少(一个线程通常只有几个),开放寻址更省内存、无需额外链表对象。


6. 五个误区

误区 真相
"ThreadLocal 存的是线程私有变量" 是"以线程为 key 的表"
"key 弱引用就不会泄漏" value 是强引用,池线程会泄漏
"用完不 remove 也没事" 线程池场景必泄漏
"ThreadLocal 可以用来做缓存" 生命周期绑线程,不是缓存
"子线程能继承父线程的 ThreadLocal" 默认不能,需 InheritableThreadLocal

7. 自检

  1. ThreadLocalMap 挂在哪?key 与 value 各是什么引用?
  2. 为什么 key 要用弱引用?这防的是什么泄漏?
  3. 线程池场景为什么会泄漏?怎么修?
  4. ThreadLocalMap 为什么用开放寻址而不是链表?
  5. 什么场景不该用 ThreadLocal?

8. 下一篇

S05-B05 · 线程池:7 个参数、拒绝策略与动态调整

ThreadLocal 解决"不共享",线程池解决"别乱建"。下一篇用实测说明"核心 2 + 队列 2 为什么第 5 个任务被拒"。


本篇属于系列《S05 · Java 并发与 JVM》。旧文来源:A-1117/1611/932/933/935/934;扩展点 E-S05-006。

S05-B04 · ThreadLocal:结构、场景与泄漏
https://www.clxhxhhr.top/posts/5245/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。