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的set方法原理示例解析

  • threadLocal通过哈希算法决定落于哪一个Entry,GC时,如果threadLocal没有引用,会被回收,即referent值为null,否则不回收,value不会回收,因此要使用remove方法删除对应Entry,否则可能会出现内存泄漏

set方法

ThreadLocal->set()

ThreadLocal的set方法原理示例解析

第一种:如果线程第一次执行set方法,此时map为空,会创建。在此过程中初始化entry的个数为16,threshold为10,同时根据哈希值定位对应下标的entry并赋值

如果map不为空,走ThreadLocalMapset方法,根据哈希值找到对应的下标。从源代码中可知:

第二种:如果该下标为空,那么直接赋值

如果该下标不为空,那么从当前下标开始遍历,直到下一个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

标签:ThreadLocal,set,方法,原理
0
投稿

猜你喜欢

  • Android无需读写权限通过临时授权读写用户文件详解

    2022-11-05 12:50:54
  • 不可不知的Android strings.xml那些事

    2022-06-04 00:14:05
  • Android自定义AvatarImageView实现头像显示效果

    2022-09-28 21:26:10
  • Java多线程中关于join方法的使用实例解析

    2023-08-22 21:47:29
  • Java实现任务超时处理方法

    2023-01-09 14:46:45
  • 面试中遇到的java逃逸分析问题

    2021-12-08 11:58:28
  • Java规则引擎Easy Rules的使用介绍

    2023-05-04 01:42:57
  • Spring的refresh()方法相关异常解析

    2021-12-08 07:39:07
  • SpringBoot项目中分页插件PageHelper无效的问题及解决方法

    2021-07-08 23:25:55
  • Lombok为啥这么牛逼?SpringBoot和IDEA官方都要支持它

    2021-10-18 23:04:50
  • Java开源工具iText生成PDF简单实例

    2022-09-12 15:06:54
  • java的各种类型转换全部汇总(推荐)

    2022-03-01 01:25:43
  • C#实现一键清空控件值的示例代码

    2021-11-12 12:10:15
  • Android编程基于Contacts读取联系人的方法(附demo源码)

    2023-11-22 06:05:39
  • 在Spring环境中正确关闭线程池的姿势

    2023-11-25 08:07:29
  • Android开发实现webview中img标签加载本地图片的方法

    2023-03-15 01:33:40
  • java fastdfs客户端使用实例代码

    2022-11-19 05:35:59
  • C#窗体实现酒店管理系统

    2023-05-23 18:58:47
  • Java开发学习 Eclipse项目有红感叹号解决之道

    2022-10-22 15:29:27
  • java之函数式接口解读

    2022-07-16 16:32:46
  • asp之家 软件编程 m.aspxhome.com