参考:
通常情况下,我们创建的变量可以被任何一个线程访问和修改。这在多线程环境中可能导致数据竞争和线程安全问题。那么,如果想让每个线程都有自己的专属本地变量,该如何实现呢?
JDK 中提供的
ThreadLocal类正是为了解决这个问题。ThreadLocal类允许每个线程绑定自己的值。
ThreadLocalMap
每个 Thread 对象内部都有一个成员变量 ThreadLocalMap。

ThreadLocalMap 是一个定制哈希表,定义在 ThreadLocal 内部,key 是 ThreadLocal 的实例(弱引用),value 是 set 进去的值(强引用)。

ThreadLocal
ThreadLocal 相当于一个工具类,对外暴露 get、set、remove 方法,在内部再通过 currentThread 拿到当前线程的 ThreadLocalMap,再操作这个 map。
存储结构示例:
Thread t1
\[0\]
├── threadLocals (ThreadLocalMap)
│ ├── Entry: key=ThreadLocal@A(弱引用), value=UserObj@X
\[1\]
│ ├── Entry: key=ThreadLocal@B(弱引用), value=UserObj@Y
│ └── …
ThreadLocal 缺点
-
内存泄漏
- 柜子钥匙(ThreadLocal 对象)是弱引用,容易被垃圾回收。
- 但柜子里面的value 是强引用,如果线程一直不死(如线程池复用),value 就永远占着内存 。
- 解决:用完一定要
finally { threadLocal.remove(); }。
-
脏读
- 线程池把同一条线程反复租给不同任务,上一次任务留下的 value 被下一次任务“误拿”,出现数据串味 。
- 解决:同上,任务开始前先
remove()。
-
不可继承
- 主线程的 ThreadLocal 值,子线程默认看不见(父子线程不同柜子)。
- 若需要传递,用
InheritableThreadLocal,但也只能传创建子线程那一刻的“快照” 。