ThreadLocal通过为每个线程提供独立变量副本实现线程隔离,数据存储在各线程的ThreadLocalMap中,set/get操作绑定当前线程,适用于请求上下文传递;但仅保证引用隔离,不解决可变对象内部状态的并发问题。

ThreadLocal 通过为每个线程提供独立的变量副本,从根本上绕开“共享”这一并发问题的源头,从而避免数据错乱。它不靠锁、不靠同步,而是用“空间换时间”的思路,让每个线程各用各的数据,互不干扰。
每个线程独占一份变量副本
ThreadLocal 并不把值存在自己内部,而是把数据存进当前线程对象(Thread)的一个私有字段 threadLocals 中——这个字段类型是 ThreadLocalMap。也就是说:
- 线程 A 的数据只在 A 的 ThreadLocalMap 里,线程 B 根本访问不到
- 即使多个线程操作同一个 ThreadLocal 实例,实际读写的是各自线程 Map 中的不同位置
- 没有共享,就没有竞争;没有竞争,自然不会错乱
set 和 get 操作天然绑定当前线程
每次调用 set() 或 get(),ThreadLocal 都会先执行 Thread.currentThread(),然后操作该线程专属的 Map:
-
threadLocal.set("user1")→ 存入当前线程的 Map,key 是这个 threadLocal 实例,value 是 "user1" -
threadLocal.get()→ 从当前线程的 Map 中,用同一个 threadLocal 实例作 key 查找 - 不同线程调用同一行代码,背后操作的是完全不同的内存区域
适合隔离线程生命周期内的上下文数据
典型场景中,一个请求由一个线程处理到底,期间需要传递用户身份、事务 ID、数据库连接等信息。把这些数据放进 ThreadLocal:
- 避免层层手动传参(如从 controller → service → dao)
- 避免使用 static 全局变量导致跨请求污染
- 只要在线程结束前调用 remove(),就不会影响下一个请求复用该线程(如线程池场景)
注意:它不解决共享对象内部状态的并发问题
ThreadLocal 保证的是“引用隔离”,不是“对象深拷贝”。如果存进去的是一个可变对象(比如 ArrayList 或自定义的非 final 类),多个线程虽然拿到的是不同引用,但如果它们都往同一个 ArrayList 里 add 元素,依然会出问题:
- 错误写法:
threadLocal.set(sharedList)(sharedList 是全局 new 的) - 正确做法:每次 set 时新建对象,或确保对象本身线程安全(如用 CopyOnWriteArrayList)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











