ThreadLocal
简介
ThreadLocal是Java中提供的实现线程局部变量的工具类,允许每个线程都拥有自己的独立副本,从而实现线程隔离,用于解决多线程中共享对象的线程安全问题,其图示如下。

使用方法
1、创建ThreadLocal变量,需指定泛型类型,代码如下:
public static ThreadLocal<String> lt = new ThreadLocal<> ();
2、对于创建的变量,调用set方法赋值。
3、调用get方法获取ThreadLocal的值。
其结构体如下:

使用场景
1、存储用户信息,在控制层拦截时可将用户信息存储到ThreadLocal中,在需要时随时取出即可;
2、数据库连接池,将数据库连接池的连接交给ThreadLocal进行管理,能够保证当前线程的操作都是同一个Connnection。
ThreadLocal原理
1、Thread 类有一个类型为ThreadLocal.ThreadLocalMap的实例变量threadLocals,每个线程都有一个属于自己的ThreadLocalMap。
2、ThreadLocalMap内部维护着Entry数组,每个Entry是一个完整的对象,key是ThreadLocal 的弱引用,value是ThreadLocal的泛型值。
3、每个线程在往ThreadLocal里设置值的时候,都是往自己的ThreadLocalMap里存,调用set方法,通过getMap方式,传入当前线程为key,获取map,从而实现了线程隔离,读也是以某个ThreadLocal作为引用。
4、栈存储Thread和ThreadLocal的引用,堆存储他们的示例值。
5、ThreadLocal本身不存储值,它只是作为一个key来让线程往ThreadLocalMap里存取值,其原理图如下。

ThreadLocal发现内存泄漏的原因
1、ThreadLocal生命周期过长,若其变量在使用后未被及时清理,则ThreadLocalMap中的键值对变量一直存在,当外部没有对该对象的引用时,会出现无法回收的情况。
2、如果一个ThreadLocal对象已经不再被使用,但是线程仍然在运行,并且其ThreadLocalMap中还保留着对这个ThreadLocal对象的键的引用,这会导致ThreadLocal对象所引用的数据也无法被回收,因为ThreadLocalMap中的键是对ThreadLocal对象的弱引用,但值是强引用。
PS:
强引用:最传统的引用,无论任何情况下,只要强引用关系还存在,垃圾收集器就永远不会回收掉被引用的对象,如Object o = new Object();
弱引用:被弱引用关联的对象只能生存到下一次垃圾收集发生时,无论当前内存是否足够,弱引用对象都会被回收。
解决方法:用完后调用remove方法。
ThreadLocalMap中,Entry 的key为弱引用,意味着当 ThreadLocal 外部强引用被置为null(ThreadLocalInstance=null)时,根据可达性分析,ThreadLocal实例此时没有任何一条链路引用它,所以系统GC的时候 ThreadLocal 会被回收。
ThreadLocalMap结构
无接口,采用元素数组存储元素,并采用散列方法把key映射到数组的对应下标。
ThreadLocalMap解决冲突的方法
使用开放地址法,在获取元素时,会根据 ThreadLocal 对象的 hash 值,定位到 table 中的位置,然后判断该槽位Entry对象中的key是否和get的key一致,如果不一致,就判断下一个位置。
ThreadLocalMap扩容机制
1、在 ThreadLocalMap.set()方法的最后,如果执行完启发式清理工作后,未清理到任何数据,且当前散列数组中Entry的数量已经达到了列表的扩容阈值(长度len的3分之2),就开始执行rehash方法。
2、rehash会先去清理过期的Entry,然后还要根据条件判断容量是否大于等于阈值的4分之3也就是来决定是否需要扩容,若满足则扩容。
3、通过resize()方法扩容,扩容后新数组的大小为老数组的两倍,然后遍历老的数组,散列方法重新计算位置,开放地址解决冲突,然后放到新的数组,遍历完成之后,老数组中所有的entry数据都已经放入到新的数组中了,然后table引用指向新数组,其代码如下:

ThreadLocal父子线程共享数据
通过InheritableThreadLocal进行,主线程在InheritableThreadLocal赋值,子线程直接调用get拿到。
本文详细介绍了Java中的ThreadLocal类,包括其使用方法、应用场景、原理、内存泄漏原因及解决策略,以及ThreadLocalMap的结构、冲突解决和扩容机制。同时提到了InheritableThreadLocal如何支持父子线程间的数据共享。
16万+

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



