ThreadLocal源码深入解析-----弱应用使用场景

我们都知道ThreadLocal可以做到每个线程独有一份副本,相互之间不影响,怎么做到的呢?
a.先来看看ThreadLocal的set方法
在这里插入图片描述
a.1 来看看set方法的大概轮廓:首先拿到当前线程,获取当前线程的threadlocalmap;如果map不为空,就将this作为key,set进去map,这里的this是set()方法的调用者,也就是threalloacl本身;如果为空,就以当前线程为参数创建一个新的map。
a.1.1 来看看getMap(t)方法,这里很简单,就是获取当前线程的一个成员变量 threadLocals
在这里插入图片描述
在这里插入图片描述
a.1.1.1 这个成员变量threadLocals里面是啥呢?其实就是一个内部类,里面维护了一个Entry数组 table,仔细看Entry这个类是继承于WeakReference的,在调用Entry构造器new对象时,会调用super(k)方法,也就是相当于我们平时创建弱应用一样WeakReference weakReference = new WeakReference<>(new ThreadLocal<>());就创建了一个弱应用指向了ThreadLocal对象,这里的k就是ThreadLocal对象,后面会有方法调用到这里
在这里插入图片描述a.1.2 可以理解为getmap方法获取到了以当前线程的threadLocal集合,接下来先来看看createMap(t, value)方法,当集合为空的时候,会调用这个方法创建一个map,具体是创建一个ThreadLocalMap对象赋值给当前对象的threadLocals成员变量,在创建ThreadLocalMap对象时,会初始化table数组,长度16,然后用firstkey(也就是ThrealLocal对象)和数组长度减一做位运算(这里相当于取模)定位firstkey的数组下标,然后创建一个Entry对象赋值到数组中,在创建Entry对象时就会产生上述a.1.1.1所说的为创建了一个弱应用指向了ThrealLocal对象。
在这里插入图片描述在这里插入图片描述
a.1.3 接下来看看map.set(this,value)方法,当getmap方法获取的集合不为空时,会调用此方法。首先tab对象指向table(Entry数组),获取数组长度,做位运算拿到数组下标i;然后拿到数组元素e,调用e.get()方法拿到ThradLocak对象,判断这个k和key相等与否,相等,就覆盖e的value值,如果k为空,就调用
replaceStaleEntry方法替换旧的Entry,如果都不满足,那就调用nextIndex(i, len)使i++再次循环直到i等于数组长度。如果在原来数组找不到以当前threadLocal对象为key的Entry,那就新建一个,size++。
在这里插入图片描述
b. 来看看ThreadLocal的get()方法
在这里插入图片描述
b.1 也是拿到当前线程的map,如果不为空,调用getEntry方法获取entry对象,拿到value值返回,如果不满足就调用setInitialValue方法初始化
b.1.1 来看看getEntry方法,用key做位运算得到数组下标,拿到数组下标元素e,如果e中的threadLocal跟key相同,返回e元素,如果不满足,就调用getEntryAfterMiss从下标i后面依次找过去,最后没找到的话,就返回null

在这里插入图片描述
在这里插入图片描述
b.1.2 接下来看看setInitialValue方法,初始化value值为null,拿到当前线程map,接下来操作跟set差不多了,就不多讲了
在这里插入图片描述
总结:每个线程都有自己的map,map里面是一个个ThreadLocal-value集合,ThreaLocal对象的弱引用为key,当外面指向这个ThreadLocal对象的强引用没了之后,遇到gc就会将ThreaLocal对象回收掉,如果map的key在这里是强引用,那么这个ThreaLocal对象永远就不会被回收了,就会产生内存泄漏,当积累多了就会产生内存溢出了。当然key用了弱应用,这里还是会有内存泄漏,因为当key所指对象被回收后,key值就是null了,那么就不能用key找到其对应的value值了,如果value是个对象,那么这个对象很有可能永远不会被回收,也会有内存泄漏,所以threadLocal用完时,要将里面的东西用remove方法清除掉

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值