1. 什么是 ThreadLocal?
ThreadLocal 可以简单理解为“线程的本地变量容器”。
打个比方:每个线程就像一个人,ThreadLocal 就像每个人身上带的专属小口袋。
- 线程往口袋里存数据,只有自己能访问,其他线程的“口袋”内容独立,互不干扰。
- 例如:线程 A 存用户 A 的信息,线程 B 存用户 B 的信息,彼此无法获取对方的数据,避免多线程数据混乱。
2. 使用 ThreadLocal 时需要注意什么?
- 及时清理数据
线程使用完后需调用remove()方法清理数据。若线程被线程池复用,未清理的残留数据可能导致后续业务逻辑出错。 避免内存泄漏
- ThreadLocalMap 的 Entry 中,key(ThreadLocal 实例)是弱引用,若 ThreadLocal 被回收,key 会变为 null,但 value 仍被强引用。
- 若线程长期存活(如线程池核心线程),value 会持续占用内存,导致泄漏。需通过
remove()主动清除 value。
- 不滥用
适合存储线程私有、多方法共享的数据(如用户上下文、事务信息),避免用它传递所有数据,否则会增加代码耦合性和调试难度。 - 父子线程数据传递
普通 ThreadLocal 的数据无法被子线程获取,若需共享可使用InheritableThreadLocal,但线程池场景下子线程可能复用,需谨慎处理。
3. ThreadLocal 常见面试题
- ThreadLocal 的作用是什么?
为每个线程提供独立的变量副本,实现线程内数据隔离,避免多线程共享变量的同步问题。 ThreadLocal 的实现原理是什么?
- 每个线程(Thread)内部有
ThreadLocalMap对象(ThreadLocal 的静态内部类)。 - ThreadLocal 实例作为 key,存储的值作为 value 存入该 map。
get()方法:获取当前线程的 ThreadLocalMap,以当前 ThreadLocal 为 key 取 value;set()方法:往 map 中存值。
- 每个线程(Thread)内部有
为什么 ThreadLocal 可能导致内存泄漏?如何避免?
- 原因:ThreadLocalMap 的 Entry 中 key 是弱引用,key 回收后 value 仍被强引用,若线程长期存活则导致内存泄漏。
- 避免:使用后调用
remove()清除 value。
ThreadLocal 和 synchronized 的区别?
- ThreadLocal:为每个线程提供独立副本,避免竞争,本质是“空间换时间”。
- synchronized:通过加锁让线程排队访问共享资源,本质是“时间换空间”。
InheritableThreadLocal 是什么?和 ThreadLocal 有何区别?
- InheritableThreadLocal 是 ThreadLocal 的子类,支持父子线程数据传递(父线程变量自动传给子线程)。
- 普通 ThreadLocal 中,子线程无法获取父线程的变量;线程池场景下子线程可能复用,需谨慎处理。
- Spring 中哪里用到了 ThreadLocal?
事务管理(如TransactionSynchronizationManager)、请求上下文(如RequestContextHolder)等,用于存储当前线程的事务信息、请求信息,保证线程内数据一致性。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。