threadlocal源码解读
时间过得真快,转眼之间已经毕业半年多了,上次从博客园写东西还是刚学springboot的时候,后来就再也没有更新过,然而现在springcloud都会用了.
话不多说开始正题,最近最看并发的一些东西 而且正好赶上 公司里抽到我分享技术,于是就分享了下ThreadLocal。
ThreadLocalMap是ThreadLocal里面的静态内部类 核心也是这个Map 今天解析的就是这个Map 其余的比如说Thread的get set过程大家有兴趣可以去看一下,其实也是调用的ThreadLocalMap中的源码。
一.ThradLocalMap,Thread,ThreadLocal关系
在讲核心内容之前 我先给大家普及一下这三者的关系,threadlocalmap是thread中的成员变量,同时也是threadlocal中的静态内部类,见下图

二.数据结构
threadlocalmap中维护一个entry数组,entry中的key其实是threadloacl的弱引用,value就是value,如下图:
大家可以看到 我们的entry节点 继承了弱引用这个类 并且在构造中通过super调用父类将我们的threadlocal引用包裹了起来,value没做处理 直接赋值.那么作者为什么要用弱引用呢?如果要是强引用的话那么 引用的threadlocal对象被置为null的话 我们的threadlocalmap还持有这个对象的强引用如果没有手动删除那么肯定不会自我清理的,但是弱引用的话 就不会这样的 因为一旦是弱引用的 一般下次gc Entry键会被回收,这个Entry就失效了,我们这个threadlocal就可以进行自己的垃圾清理机制了,因为我们的threadlocalmap跟thread的生命周期一样长,同样的条件下明显 弱引用相当于多了一层保障。
三.怎样解决哈希冲突
theadLocalmap中解决哈希冲突的办法是开放定址法,言简意赅就是发生哈希冲突的话,去寻找没有被占用的位置进行插入,去寻找位置是有方法的而不是没有目的的盲目去寻找,这个方法我们叫做探查方法,开放定址法的探查方法有三种,一是线性探查,二是二次探查,三是双重散列,双重散列是探查方法中最好的,因为它找的位置足够随机,没有那么严重的群集问题 其次是二次探查 ,最后才是线性探查,有兴趣的同学可以自行查询学习下,在这里我其实一直有一个疑问那为什么我们的threadlocalmap解决哈希冲突使用的是线性探查 而不是双重散列????
四.set
第一步开始线性探查 要是探测过程中命中了就将value替换掉,如果探测过程中发现有位置是失效(位置1)的了 那么就开始从这个位置向前找查找最前面一个失效的位置(位置2),然后从这个失效位置(位置1)向后遍历table,如果在向后遍历的过程中命中了那么就将entry替换到位置1,而这个位置恰巧就是之前找到的最前面的那个失效的位置(位置2)的话,那么就以这个位置进行清理,如果不是的话 那么以最前面的那个失效的位置(位置2)进行清理,其实就是没有命中的话 一定会将这个k,v替换到没有命中的那个失效得位置(位置1)上,如果在向后的探测中并没有命中key那么就new一个entry将这个失效的位置(位置1)替换掉,要是探测过程中没有发现失效的 也没有命中 那么就在entry数组最后在新添加一个。
五.getEntry
getEntry相比于set方法来说 简单太多了
一上来要是直接找到的话 那么直接返回这个entry,没有找到的话进行就开始向后探测这个entry 因为向后探测 还是有可能找到的。如果再向后探测过程中 如果·发现有 失效的Entry 将这个失效的位置清理掉 数组长度 减一,并且将从这个位置开始 向后寻找最后一个空位置,在这个区间将所有失效的entry都清除掉。

浙公网安备 33010602011771号