ThreadLocal 原理
ThreadLocal 中有一个内部类ThreadLocalMap,用于存储线程局部变量。ThreadLocalMap 是一个 HashMap,其 Key 是 ThreadLocal 实例,Value 是线程本地变量。每个 Thread 实例内部都包含一个 ThreadLocalMap。当线程调用 ThreadLocal 的 set 方法时,会将值存储在当前线程的 ThreadLocalMap 中。当线程调用 ThreadLocal 的 get 方法时,会从当前线程的 ThreadLocalMap 中获取对应的值。由于每个线程都有自己的 ThreadLocalMap,因此实现了线程隔离,避免了线程间的数据共享。
ThreadLocal 的作用
线程隔离: ThreadLocal 为每个线程提供一个独立的变量副本,避免了多线程环境下共享变量带来的问题,例如线程安全问题、数据竞争等。
数据传递: ThreadLocal 可以方便地在同一个线程的不同函数之间传递数据,避免了通过参数传递带来的耦合。
避免使用全局变量: ThreadLocal 可以避免使用全局变量,减少全局变量的作用范围,提高代码的可维护性。
ThreadLocal 实现线程隔离
每个 ThreadLocal 实例都关联一个 ThreadLocalMap,存储该线程的所有线程局部变量。ThreadLocalMap 的键是 ThreadLocal 实例,值是线程局部变量的值。由于 ThreadLocalMap 只存储当前线程的线程局部变量,因此不同的线程拥有不同的 ThreadLocalMap 实例,实现了线程隔离。
ThreadLocalMap中Entry 会使用弱引用对 Key 进行包装,而不是直接使用 Threadlocal 实例作为 Key。
什么是弱引用?仅有弱引用(WeakReference)指向的对象,只能生存到下一次垃圾回收之前。换句话说,当 GC 发生时,不管内存够不够,仅有弱引用所指向的对象都会被回收。而拥有强引用指向的对象,则不会被直接回收。
ThreadLocalMap 中 Entry 的 Key 使用了弱引用,在下次 GC 发生时,就可以使那些没有被其他强引用指向、仅被 Entry 的 Key 所指向的 ThreadLocal 实例能被顺利回收。并且,在 Entry的 Key 引用被回收之后,其 Entry 的 Key 值变为 null。后续当 ThreadLocal 的 get、set 或 remove 被调用时,ThreadLocalMap 的内部代码会清除这些 Key 为 null 的 Entry,从而完成相应的内存释放。防止发生内存泄漏。
ThreadLocal 会发生内存泄漏的前提条件: (1)线程长时间运行而没有被销毁。线程池中的 Thread 实例很容易满足此条件。
(2)ThreadLocal 引用被设置为 null,且后续在同一 Thread 实例的执行期间,没有发生对其他 ThreadLocal 实例的 get、set 或 remove 操作。
本文作者:whitebear
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!