ThreadLocal
ThreadLocal 是 Java 提供的线程本地变量(Thread Local Variable)机制:
作用:给每个线程 分配一份独立的变量副本,互不干扰,避免多线程环境下的共享冲突问题。
特点:同一个 ThreadLocal
变量,在不同线程中有不同的值(隔离性)。
本质:每个线程内部有个 ThreadLocalMap
,ThreadLocal
作为 key
,自己存自己的值。
public class ThreadLocalDemo {
private static ThreadLocal threadLocal = ThreadLocal.withInitial(() -> 0);
public static void main(String[] args) {
Runnable task = () -> {
threadLocal.set((int) (Math.random() * 100));
System.out.println(Thread.currentThread().getName() + ":" + threadLocal.get());
};
new Thread(task, "线程A").start();
new Thread(task, "线程B").start();
}
}
✅ 输出示例:
线程A:83
线程B:24
各线程独立,互不干扰。
ThreadLocalMap
ThreadLocal.ThreadLocalMap threadLocals;
存储当前线程的所有 ThreadLocal
变量
ThreadLocal
对象作为 key
真正的数据存在 ThreadLocalMap.Entry
中
// 存
threadLocal.set("abc");
// 本质:Thread.currentThread().threadLocals.put(threadLocal, "abc");
// 取
threadLocal.get();
// 本质:Thread.currentThread().threadLocals.get(threadLocal);
因为数据存储在当前线程的 ThreadLocalMap
中,每个线程有自己的副本,自然互不干扰。
场景 | 说明 |
---|---|
✅ 数据库连接 Connection | 每个线程绑定一个 Connection,避免频繁创建销毁 |
✅ 事务管理 | 线程内管理事务、Session |
✅ 用户登录信息存储 | 比如保存用户 userId ,在整个请求链路中随时取 |
✅ SimpleDateFormat | 线程不安全,配合 ThreadLocal 解决并发问题 |
✅ 防止线程间共享污染 | 保证每个线程数据独立 |
ThreadLocal
会引发内存泄漏?ThreadLocalMap
的 key 是弱引用(WeakReference),value
是强引用
如果 ThreadLocal
被 GC 回收,但 ThreadLocalMap
里的 value 没清除,value 永远被线程引用
特别是 线程池中的线程长时间不销毁,容易发生泄漏
✅ 用完一定调用 remove()
,及时清理:
try {
threadLocal.set("xxx");
// 业务处理
} finally {
threadLocal.remove(); // 防止内存泄漏
}
InheritableThreadLocal
(子线程继承)场景:ThreadLocal
数据传递到子线程中
InheritableThreadLocal local = new InheritableThreadLocal<>();
local.set("main");
new Thread(() -> {
System.out.println(local.get()); // 输出 "main"
}).start();
✅ 适合做上下文传递,如 分布式链路追踪 TraceId
方法 | 作用 |
---|---|
set(T value) |
设置当前线程的局部变量值 |
get() |
获取当前线程的局部变量值 |
remove() |
删除当前线程的局部变量,防止内存泄漏 |
withInitial(Supplier supplier) |
初始化默认值(JDK 8+) |
面试问题 | 高分回答要点 |
---|---|
为什么要用 ThreadLocal? | 解决多线程共享变量冲突,做到线程内独享,隔离性强。 |
底层原理? | 每个线程维护一个 ThreadLocalMap ,ThreadLocal 作为 key,存储线程私有数据。 |
内存泄漏风险? | key 弱引用,value 强引用,及时 remove() 防止泄漏,尤其线程池场景。 |
和 synchronized、锁区别? | ThreadLocal 不是用来解决线程安全的共享问题,而是隔离数据,互不共享,避免加锁。 |
ThreadLocal
本质是线程内的局部存储工具,适合解决“只想让线程自己玩,不共享”的场景,但必须注意 remove()
,否则容易内存泄漏。