文章目录
多线程基础系列-ThreadLocal
一、ThreadLocal核心定义
ThreadLocal(线程本地变量)是Java提供的线程私有存储工具类,核心作用是:为每个使用该变量的线程创建一个独立的副本,线程只能访问自己的副本,不同线程之间的副本互不干扰。
可以用一个通俗的比喻理解:
- 普通变量:像办公室的公共白板,所有线程(同事)都能看到、修改,需要加锁保证安全;
- ThreadLocal变量:像每个同事的私人笔记本,每个人只能写自己的本子,不用和别人抢,天然线程安全。
二、ThreadLocal核心工作原理
ThreadLocal的底层不是把变量存在自己的对象里,而是存在每个Thread线程对象的ThreadLocalMap中:
- 每个Thread对象内部维护一个
ThreadLocalMap(类似HashMap的结构); - ThreadLocal作为
ThreadLocalMap的key,线程私有数据作为value; - 当线程通过
ThreadLocal.set()存值时,实际是往当前线程的ThreadLocalMap中存(key=当前ThreadLocal实例,value=要存储的值); - 当线程通过
ThreadLocal.get()取值时,实际是从当前线程的ThreadLocalMap中取; - 线程结束后,ThreadLocalMap会被销毁,对应的副本数据也会被回收。




三、ThreadLocal基础使用示例
public class ThreadLocalDemo {
// 定义ThreadLocal变量,指定存储String类型
private static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<>();
public static void main(String[] args) {
// 线程1:存值并取值
new Thread(() -> {
THREAD_LOCAL.set("线程1的私有数据");
System.out.println(Thread.currentThread().getName() + ":" + THREAD_LOCAL.get()); // 输出:Thread-0:线程1的私有数据
// 手动移除,避免内存泄漏
THREAD_LOCAL.remove();
}, "Thread-0").start();
// 线程2:存值并取值
new Thread(() -> {
THREAD_LOCAL.set("线程2的私有数据");
System.out.println(Thread.currentThread().getName() + ":" + THREAD_LOCAL.get()); // 输出:Thread-1:线程2的私有数据
THREAD_LOCAL.remove();
}, "Thread-1").start();
}
}
四、ThreadLocal的核心应用场景
- 保存线程上下文信息:比如在Web开发中,把用户登录信息(User对象)存入ThreadLocal,整个请求链路的所有方法都能直接获取,无需层层传参;
- 解决线程安全问题:比如SimpleDateFormat是非线程安全的,每个线程通过ThreadLocal持有自己的SimpleDateFormat副本,避免加锁;
// 示例:ThreadLocal封装SimpleDateFormat private static final ThreadLocal<SimpleDateFormat> DATE_FORMATTER = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd")); // 线程中使用:DATE_FORMATTER.get().format(new Date()) - 数据库连接管理:每个线程持有自己的数据库连接(Connection),避免多线程共享连接导致的事务问题。
五、ThreadLocal的核心注意事项
- 内存泄漏风险:
- 原因:ThreadLocalMap的key是ThreadLocal的弱引用,当ThreadLocal实例被回收后,key变为null,但value是强引用,会导致value无法被回收,最终造成内存泄漏;
- 解决:使用完ThreadLocal后,务必调用
remove()方法手动移除值(阿里开发规范中也有要求)。

- 不能解决共享数据的线程安全问题:ThreadLocal是让每个线程有自己的副本,而非共享数据,若要处理多线程共享数据,仍需用锁。
- InheritableThreadLocal:如果需要让子线程继承父线程的ThreadLocal值,可以使用
InheritableThreadLocal(比如主线程的用户信息传递给子线程)。
总结
- 核心作用:ThreadLocal为每个线程创建独立的变量副本,实现线程私有数据存储,天然避免多线程竞争;
- 底层原理:数据存储在每个Thread的ThreadLocalMap中,ThreadLocal作为key,线程仅能访问自己的副本;
- 关键注意:使用后必须调用
remove()避免内存泄漏,它适用于“线程私有数据”场景,而非共享数据场景。

4110

被折叠的 条评论
为什么被折叠?



