ThreadLocal的set方法原理示例解析
作者:yunmengmeng 发布时间:2023-11-09 15:06:09
前沿知识
ThreadLocal
存储线程变量,使用set
方法设置变量,使用get
方法获取变量线程隔离的实现是每个
Thread
类有一个类型为ThreadLocal.ThreadLocalMap
的实例变量threadLocals
。如下图所示,ThreadLocalMap
内部有一个Entry
数组,每个Entry
的key是ThreadLocal
,也就是referent
对象,value是设置的值;该类的size变量记录当前数组使用容量;threshold变量记录阈值,默认总容量的三分之二,初始是10
threadLocal
通过哈希算法决定落于哪一个Entry
,GC时,如果threadLocal
没有引用,会被回收,即referent
值为null
,否则不回收,value不会回收,因此要使用remove
方法删除对应Entry
,否则可能会出现内存泄漏
set方法
ThreadLocal->set()
:
第一种:如果线程第一次执行set方法,此时map为空,会创建。在此过程中初始化entry的个数为16,threshold为10,同时根据哈希值定位对应下标的entry并赋值
如果map不为空,走ThreadLocalMap
的set
方法,根据哈希值找到对应的下标。从源代码中可知:
第二种:如果该下标为空,那么直接赋值
如果该下标不为空,那么从当前下标开始遍历,直到下一个entry为null时停止
第三种:如果entry的key是当前thread,直接替换值
第四种:如果循环结束,说明遇到了空entry,那么直接赋值到该下标
如果之前发生了GC,那么entry不为空,但是key为空,此时调用replaceStaleEntry
方法
记录此下标为staleSlot、slotToExpunge
变量,从当前下标的前一个entry开始遍历,直到entry为null时停止,如果有回收的entry,那么记录它的下标,赋值到slotToExpunge
变量
从当前下标的后一个entry开始遍历,直到entry为null时停止
第五种:如果遇到了key相等的情况,那么替换值,该entry与staleSlot下标的entry交换。如果向前遍历没有找到回收的entry,那么记录并赋值到slotToExpunge
变量。清理过期entry,最后返回
第六种:如果循环结束,说明遇到了空entry,也没有找到key相等的entry。那么清除staleSlot下标的value,然后新建entry。如果有记录过期entry,那么会清理,最后返回
赋值结束后,还会进行一次尝试清理,如果没有过期entry,并且当前容量大于等于阈值,走扩容rehash
方法
清理与扩容
expungeStaleEntry(staleSlot)
:由于传入的下标staleSlot所在entry一定是GC之后的,因此会将entry的值设为null,随后删除entry。从下一个entry开始遍历,直到entry为null时停止,如果entry是GC过的,将value置为null,否则将key重新哈希和分配,这样的目的是使得entry离正确的下标位置更接近一些。最后返回entry为null的坐标
cleanSomeSlots(i,n)
:参数n一般是当前的size值。从i的下一个entry开始遍历,每遍历一次,n的值就减少一半,直到为0时停止。如果所在下标的entry是GC过的,那么会调用一次expungeStaleEntry(staleSlot)
方法
rehash()
:首先调用一次清理方法,然后判断当前容量是否超过阈值的四分之三(约总容量的二分之一),然后才真正扩容,每次扩容一倍。循环遍历entry数组,如果entry发生GC,那么将值设置为null,否则将key重新哈希和分配,最后重新计算阈值和当前使用容量
来源:https://juejin.cn/post/7201730884373561401


猜你喜欢
- 本人亲测,在使用IDEA使用Maven模板创建项目或者在当前项目中New Project,Maven的以下三个配置参数会重置使用C:\Use
- 前言对于Android注解,或多或少都有一点接触,但相信大多数人都是在使用其它依赖库的时候接触的。因为有些库如果你想使用它就必须使用它所提供
- 本文基于shardingsphere-jdbc-core-spring-boot-starter 5.0.0,请注意不同版本的shardin
- 1、添加maven依赖<dependency>  
- 本文实例讲述了C#检测DataSet是否为空的方法。分享给大家供大家参考。具体如下:下面的代码片段通过判断DataSet的Table数量来判
- 文件作为存储数据的单元,会根据数据类型产生很多分类,也就是所谓的文件类型。在对数据文件进行操作时,常常需要根据不同的文件类型来作不同的处理。
- 实现流程初始化一定数量的任务处理线程和缓存线程池,用户每次调用接口,开启一个线程处理。假设初始化5个处理器,代码执行 BlockingQue
- 我们都知道取消标题栏有两种方式,一种是在Java代码中取消,另一种通过设置styles.xml文件中的Theme即可;如下图:第一种:第二种
- 一、Synchronized的基本使用Synchronized是Java中解决并发问题的一种最常用的方法,也是最简单的一种方法。Synchr
- 一、前言文稿扫描大家用的都比较频繁、想是各种证件、文件都可以通过扫描文稿功能保存到手机。相比直接拍照,在扫描文稿时,程序会对图像进行一些矫正
- 本文实例为大家分享了winform可拖动的自定义Label控件,供大家参考,具体内容如下效果预览:实现步骤如下:(1)首先在项目上右击选择:
- 前言在实际开发中我们经常会与时间打交道,那这就会涉及到一个时间格式转换的问题。接下来会介绍几种在SpirngBoot中如何对时间格式进行转换
- 本篇介绍了SpringBoot 缓存(EhCache 2.x 篇),分享给大家,具体如下:SpringBoot 缓存在 spring Boo
- 目录1、如果类的方法没有返回值,该方法的返回值类型应当是abstract。()2、代码String str=”123456a”;int i=
- 具体可见http://developer.android.com/tools/debugging/ddms.html。 DDMS为IDE和e
- 最终效果项目地址https://github.com/Tecode/flutter_widget实现方法安装插件安装video_player
- 本文实例为大家分享了android TextView跑马灯效果的具体代码,供大家参考,具体内容如下一、要点设置四个属性android:sin
- @Value取值为NULL的问题在spring mvc架构中,如果希望在程序中直接使用properties中定义的配置值,通常使用一下方式来
- webclient在调用DownloadData或者DownloadString的时候请求回来的数据出现乱码问题,解决办法如下:1、设置we
- 最近再开发中遇到需要将文件上传到Linux服务器上,至此整理代码笔记。此种连接方法中有考虑到并发问题,在进行创建FTP连接的时候