并发编程之ThreadLocal底层原理探析

源码略我千百遍,我待源码如初恋

1、为什么要引用ThreadLocal

线程副本,存放线程变量,在线程任务中进行跨方法变量传递,相比于锁以时间换空间的方式,ThreadLocal是采用以空间换时间

2、ThreadLocal源码解析

1、打开ThreadLocal源码,先看看整体结构,构造方法,核心方法set(t) , get(),remove(),核心内部类ThreadLocalMap

2、ThreadLcoal.set(value)方法,通过源码走读,可以清晰看懂ThreadLocalMap对象是Thread线程对象里面的一个属性,并且Map存的键值对是当前ThreadLocal对象,和传入的value值

3、ThreadLocalMap对象:在上面set方法中如果map为空,则初始化创建ThreadLocalMap对象,ThreadLcoalMap是ThreadLocal内部定义的类,内部定义了一个entry内部类,和hashMap的内部entry实现原理类似。内部有一个table数组,以及定义了一些相关属性,如初始长度,大小,临界长度等等

set源码整体实现比较简单,主要是弄清ThreadLocal存的key value对应的对象,以及ThreadLocalMap内部类的构造

4、ThreadLocal.get()方法:获取当前线程,通过线程获取对象ThreadLocalMap,通过getEntry(this)方法获取对象的value值,如果map为空,调用setInitialValue()方法返回一个null值。

5、remove方法 移除ThreadLocalMap缓存的ThreadLocal对象及对应的value,释放内存空间

ThreadLocal为何会内存泄露:

当把 threadlocal 变量置为 null 以后,没有任何强引用指向 threadlocal 实例,所以threadlocal 将会被 gc 回收。这样一来, ThreadLocalMap 中就会出现 key 为 null 的 Entry,就没有办法访问这些 key 为 null 的 Entry 的 value,如果当前 线程再迟迟不结束的话,这些 key 为 null 的Entry 的 value 就会一直存在一条强 引用链: Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value ,而这块 value 永 远不会被访问到了,所以存在着内存泄露。

只有当前 thread 结束以后, current thread 就不会存在栈中,强引用断开, Current Thread 、Mapvalue 将全部被 GC 回收。最好的做法是不在需要使用ThreadLocal 变量后,都调用它的 remove()方法,清除数据。

拓展:如何解决Hash冲突

开放定址法:

基本思想是,出现冲突后按照一定算法查找一个空位置存放,根据算法的不同又可以分为线性探测再散列、二次探测再散列、伪随机探测再散列。线性探测再散列即依次向后查找,二次探测再散列, 即依次向前后查找, 增 量为 1 、2 、3 的二次方,伪随机,顾名思义就是随机产生一个增量位移。

ThreadLocal 里用的则是线性探测再散列

链地址法:

这种方法的基本思想是将所有哈希地址为 i 的元素构成一个称为同义词链的单链表, 并将单链表的头指针存在哈希表的第 i 个单元中, 因而查找、插入和删 除主要在同义词链中进行。链地址法适用于经常进行插入和删除的情况

再哈希法:

这种方法是同时构造多个不同的哈希函数: Hi=RH1(key) i=1 ,2 ,… ,k 当哈希地址 Hi=RH1(key)发生冲突时,再计算 Hi=RH2(key)……,直到冲突 不再产生。这种方法不易产生聚集,但增加了计算时间。

建立公共溢出区

这种方法的基本思想是: 将哈希表分为基本表和溢出表两部分, 凡是和基本 表发生冲突的元素, 一律填入溢出表。

  • 8
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值