Threadlocal 和 ThreadLocalMap 原理解析

java 中提供了两个线程安全的操作方式,一个是 Threadlocal ,一个是ThreadLocalMap。本文介绍他们的区别和实现原理。

Threadlocal
Threadlocal 的属性包括 threadLocalHashCode,getMap(Thread t) 到当前线程去获取一个 ThreadLocalMap 的内部类对象,它的属性有一个 entry 数组,数组下标是当前 Threadlocal 对应的hash值,entry 对象是一个 WeakReference 对象,存放对应 Threadlocal 需要保存的变量值 value。

ThreadLocal 用于提供线程局部变量,通过它的 get() 和 set() 方法访问某个变量相应线程自己的局部变量。但在这里需要注意的是,它是通过各个线程自己创建对象然后调用这里的set方法设置进去,而不是由 ThreadLocal 自己来创建变量的副本的。

ThreadLocalMap
通过Entry数组保存局部变量。通过key(ThreadLocal类型)的hashcode来计算数组存储的索引位置i。如果i位置已经存储了对象,那么就往后挪一个位置依次类推,直到找到空的位置,再将对象存放。另外,在最后还需要判断一下当前的存储的对象个数是否已经超出了阈值(threshold的值)大小,如果超出了,需要重新扩充并将所有的对象重新计算位置。

线程保存ThreadLocalMap对象,对象主要通过Entry[]数组存放键{threadlocal}值,通过threadlocal的threadLocalHashCode定位存放数组位置,Entry extendsWeakReference<ThreadLocal> 的value保存变量副本,通过Entry.get获取threadlocal。

如果这里使用普通的key-value形式来定义存储结构,实质上就会造成节点的生命周期与线程强绑定,只要线程没有销毁,那么节点在GC分析中一直处于可达状态,没办法被回收,而程序本身也无法判断是否可以清理节点。弱引用是Java中四档引用的第三档,比软引用更加弱一些,如果一个对象没有强引用链可达,那么一般活不过下一次GC。当某个ThreadLocal已经没有强引用可达,则随着它被垃圾回收,在ThreadLocalMap里对应的Entry的键值会失效,这为ThreadLocalMap本身的垃圾清理提供了便利。

ThreadLocal

ThreadLocalMap维护了Entry环形数组,数组中元素Entry的逻辑上的key为某个ThreadLocal对象(实际上是指向该ThreadLocal对象的弱引用),value为代码中该线程往该ThreadLoacl变量实际塞入的值。

从ThreadLocal读一个值可能遇到的情况:根据入参threadLocal的threadLocalHashCode对表容量取模得到 index

如果index对应的slot就是要读的threadLocal,则直接返回结果
调用getEntryAfterMiss线性探测,过程中每碰到无效slot,调用expungeStaleEntry进行段清理;如果找到了key,则返回结果entry
没有找到key,返回null
ThreadLocal的set方法可能会有的情况。

探测过程中slot都不无效,并且顺利找到key所在的slot,直接替换即可
探测过程中发现有无效slot,调用replaceStaleEntry,效果是最终一定会把key和value放在这个slot,并且会尽可能清理无效slot
 

在replaceStaleEntry过程中,如果找到了key,则做一个swap把它放到那个无效slot中,value置为新值
在replaceStaleEntry过程中,没有找到key,直接在无效slot原地放entry
探测没有发现key,则在连续段末尾的后一个空位置放上entry,这也是线性探测法的一部分。放完后,做一次启发式清理,如果没清理出去key,并且当前table大小已经超过阈值了,则做一次rehash,rehash函数会调用一次全量清理slot方法也即expungeStaleEntries,如果完了之后table大小超过了threshold – threshold / 4,则进行扩容2倍
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值