ThreadLocal 的工作原理
ThreadLocal
是一个 静态工具类,全局只有一个定义。
但它存放的数据并不是存在 ThreadLocal
对象里,而是存在 线程对象内部的 threadLocals
中。
1️⃣ ThreadLocal 的核心代码
public class ThreadLocal<T> {public void set(T value) {Thread t = Thread.currentThread(); // 获取当前线程ThreadLocalMap map = getMap(t); // 每个线程有一个 mapif (map != null) {map.set(this, value); // this 就是 ThreadLocal 实例(key)} else {createMap(t, value); // 如果 map 为空则新建}}public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {return (T) map.get(this); // 根据 this 取值}return null;}
}
2️⃣ Thread 类里的成员
class Thread {ThreadLocal.ThreadLocalMap threadLocals = null; // 每个线程自己维护一份
}
也就是说,值是存在 线程对象的 threadLocals
里,而不是在 ThreadLocal
对象本身。
3️⃣ ThreadLocalMap 的结构
每个线程的 ThreadLocalMap
内部维护:
Entry[] table; // Entry 是 ThreadLocal -> value 的映射static class Entry extends WeakReference<ThreadLocal<?>> {Object value;Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}
}
也就是说:
- key = ThreadLocal 实例
- value = 存进去的对象
4️⃣ 示例结构图
Thread (线程)└── ThreadLocalMap (存放数据的容器)├── Entry(ThreadLocalA -> "userId=1001")├── Entry(ThreadLocalB -> "traceId=abc123")└── Entry(ThreadLocalC -> "dateFormat=yyyy-MM-dd")
这里的 ThreadLocalA/B/C
就是不同的 ThreadLocal
对象,它们是 key。
这样,每个 ThreadLocal
就能“命中”自己那份数据,互不干扰。
5️⃣ 弱引用的作用
ThreadLocalMap.Entry
继承了 WeakReference<ThreadLocal<?>>
:
- key(ThreadLocal 对象)是 弱引用,当
ThreadLocal
没有被外部引用时,GC 会自动回收 key - 对应的 value 是强引用,不会被自动回收。
- 这就是所谓的 ThreadLocal 内存泄漏 问题。