ThreadLocal源码阅读二:如何保证取到最新值的?

背景
  1. ThreadLocal是怎么保证取到最新值的?比如,一个Integer类型的值,假如默认是0。现在,先执行一次set操作,值为1;然后在执行一次set操作,值为2。这个时候执行get操作,发现拿到的值是2。
过程
  • 散列算法运作过程

    1. 理解ThreadLocal中散列算法是怎么工作的演示例子

      在这里插入图片描述

    2. 结果
      在这里插入图片描述

    3. 结论
      当执行第17次的时候,又从头开始循环了。

      按照这样完美的散列去分析,也会出现hash碰撞吗?如果entry[ ]不扩容,则必然会有hash碰撞。如果扩容,可能会存在hash碰撞,但是概率小。

  • ThreadLocal#set方法源码

    假如我们设置的默认值是0,而这个时候,没有执行任何方法

    假如,tab代表Entry[],每执行一次set操作,自增1。tab默认长度是16,size是0。num代表ThreadLocal实例。散列值顺序是 7 14 5 12 3 10 1 8 15 6 13 4 11 2 9 0 。

    当加载含ThreadLocal实例的类,并初始化这个类的时候,ThreadLocal实例的threadLocalHashCode属性被赋值成功,此属性是final修饰的,因此不可修改,后续需要的时候,直接使用即可。假如,7 = threadLocalHashCode & ( 16 -1)

    当第一次执行set操作的时候,那么tab就需要创建一个entry实例,假如为entry01,key是num实例的地址,value是1。tab[7] = entry01(num_addr, 1),tab的长度是16,size是1。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    当第二次执行set操作的时候,map不为null,此时tab[7] = entry01(num_addr, 2),tab的长度还是16,size还是1。
    在这里插入图片描述
    在这里插入图片描述
    目前tab中布局就是:tab[7] = entry01(num_addr, 2)

  • get方法源码

    这个时候,执行一次get操作,根据hash算法,那么这个Entry entry = tab[7],获取到这个entry01这个实例
    在这里插入图片描述
    在这里插入图片描述

  • 疑问

    key(ThreadLocal)是一个弱引用。如果程序没有主动置null,那么下次GC的时候就一定可以被回收掉吗?

    不是。想象一下,线程执行是一段时间,如果完成对ThreadLocal的使用,但是没有置null,那么下次GC的时候,ThreadLocal会被GC掉。如果线程执行的这一段时间中,后续代码逻辑有使用到ThreadLocal实例,那在执行后续代码逻辑之前,发生GC的时候,无法GC掉ThreadLocal实例。只有当线程没有对ThreadLocal实例进行使用了,但是线程没有退出,那么下次GC的时候,ThreadLocal将会被回收,但是值v是不会被GC的,因为线程还在进行中。

    为什么要弱引用ThreadLocal?

    这是一个保护措施。假如一个线程的ThreadLocalMap中包含了100w个Entry实例,那么相应就有100w个ThreadLocal实例和100w个v。如果线程在运行中,但是都已经完成了对ThreadLocal的使用,那么下次GC的时候,一定可以把ThreadLocal全部GC掉。如果不是弱引用,那么这100w个ThreadLocal实例将一直等到线程结束后,才能回收。

小结
  1. 对应关系

    一个Thread只有一个ThreadLocalMap

    一个ThreadLocalMap对应多个ThreadLocal

    一个ThreadLocal实例对应一个Entry实例

    一个ThreadLocal实例只有唯一一个threadLocalHashCode

  2. 每次设置值的时候

    如果没有Entry实例,则创建一个新的Entry实例

    如果有Entry实例,则在已有的Entry实例上更新值即可

  3. 每次创建新的Entry,则一定是ThreadLocal实例第一次执行set方法,或者第一次执行get方法。

  4. 当加载含ThreadLocal实例的类,并初始化这个类的时候,ThreadLocal实例的threadLocalHashCode属性值被赋值成功,此属性是final修饰的,因此不可修改,后续需要的时候,直接使用即可

  5. 理解对应关系,理解threadLocalHashCode唯一,才能明白为什么能够取到最新值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值