这玩意比ThreadLocal叼多了,吓得why哥赶紧分享出来。 (4)

简介: 这玩意比ThreadLocal叼多了,吓得why哥赶紧分享出来。 (4)

标号为 ① 的地方就是往 InternalThreadLocalMap 这个数组中存放我们传进来的 value。

存的时候分为两种情况。


标号为 ② 的地方是数组容量还够,能放进去,那么可以直接设置。


标号为 ③ 的地方是数组容量不够用,需要扩容了。


这里抛出两个问题:


扩容是怎么扩的?


数组下标是怎么来的?


先看问题一,怎么扩容的?


看源码:



image.png


和 HashMap 里面的位运算异曲同工。


在 InternalThreadLocalMap 中扩容就是变成原来大小的 2 倍。从 32 到 64,从 64 到 128 这样。


扩容完成之后把原数组里面的值拷贝到新的数组里面去。


然后剩下的部分用 UNSET 填充。最后把我们传进来的 value 放到指定位置上。


再看看问题二,数组下标怎么来的?也就是这个 index:


微信图片_20220426232104.png


从上往下看,可以看到最后,这个 index 本质上是一个 AtomicInteger 。


主要看一下标号为 ① 的地方。


index 每次都是加一,对应的是 InternalThreadLocalMap 里的数组下标。


第一眼看到的时候,里面的 if 判断 index<0 我是可以理解的,防止溢出嘛。


但是下面在抛出异常之前,还调用了 decrementAndGet 方法,又把值减回去了。


你说这是为什么?


开始我没想明白。但是有天晚上睡觉之前,电光火石一瞬间我想明白了。


image.png


如果不把值减回去,加一的代码还在不断的被调用,那么这个 index 理论上讲是有可能又被加到正数的,这一点你能明白吧?


为什么我说理论上呢?


int 的取值范围是 [-2147483648 到 2147483647]。


如果 int 从 0 增加,一直溢出到 -2147483648,再从 -2147483648 加到 0,中间有 4294967295 个数字。


一个数字对应数组的一个下标,就算里面放的是一个字节的 boolean 型,那么大概也就是 4T 的内存吧。


所以,我觉得这是理论上的。


到这一步,我们已经完成了从 Thread 里面取出 InternalThreadLocalMap ,并且往里面放数据的操作。


最后,InternalThreadLocal 的 set 方法只剩下最后一行代码,我们还没说:



image.png


就是 setIndexedVariable 方法返回 true 后,会执行 addToVariablesToRemove 方法。


这个方法其实就是在数组的第一个位置维护当前线程里面的所有的 InternalThreadLocalMap 。


这里的关键点其实就是这个变量:


image.png


static final,能保证 VARIABLE_TO_REMOVE_INDEX 恒等于 0,也就是数组的第一个位置。


用示例程序,给大家演示一下,它第一个位置放的东西:


image.png


在第 21 行打上断点,然后看一下执行完 addToVariablesToRemove 方法后,InternalThreadLocalMap 数组的情况:



image.png


诚不欺你,第 0 个位置上放的是所有的 InternalThreadLocal 的集合。


所以,我们看一下它的 size 方法,就能明白这里为什么要减一了:


那么在第一个位置维护线程里面所有的 InternalThreadLocal 集合的用处是什么?


看看它的 removeAll 方法:


image.png

目录
相关文章
|
4天前
|
Java
面试官:说一说CyclicBarrier的妙用!我:这个没用过...
面试官:说一说CyclicBarrier的妙用!我:这个没用过...
13 2
|
9月前
|
Java
Java多态面试题汇总含答案
Java多态面试题汇总含答案
83 0
|
存储 缓存 Java
终于弄明白了ThreadLocal
ThreadLocal是Thread的局部变量,用于编多线程程序,对解决多线程程序的并发问题有一定的启示作用。
117 0
终于弄明白了ThreadLocal
|
存储 安全 算法
还怕被问到Java集合?看到这篇文章就够了!!!
还怕被问到Java集合?看到这篇文章就够了!!!
125 0
还怕被问到Java集合?看到这篇文章就够了!!!
|
算法 安全 Java
threadlocal再温习
早时总结过《ThreadLocal解析》、《FastThreadLocal解析》 最近看一些资料的时候,又重重发现了这类,不希望再温下,许多知识点,之前已经总结了,这篇文章主要有两个问题: 1、弱引用的意义 2、如何防键冲突
201 0
threadlocal再温习
烧点脑子使劲看--HashMap源码分析(下)
构造方法 HashMap一共有四个构造
100 0
|
安全
烧点脑子使劲看--HashMap源码分析(上)
概述 HashMap最早出现在JDK1.2中,是基于Map接口的实现,储存的内容是键值对(key-value),HashMap中的键和值都可以为null。HashMap的实现并不是同步的,也就是说它不是线程安全的。
81 0
|
监控 C语言 iOS开发
小码哥底层原理之RunLoop
RunLoop是一个运行循环,保证App能够持续运行,处理各种事件,节省CPU资源,没事处理的时候就进入休眠。
129 0
小码哥底层原理之RunLoop
|
存储 安全 算法
面试:为了进阿里,死磕了ConcurrentHashMap源码和面试题(二)
在上篇《面试:为了进阿里,死磕了ConcurrentHashMap源码和面试题(一)》,研究了基础原理,以及ConcurrentHashMap数据put的流程等线程安全的,来回顾一下面试的问题点
145 0
面试:为了进阿里,死磕了ConcurrentHashMap源码和面试题(二)
|
存储 安全 算法
面试:为了进阿里,死磕了ConcurrentHashMap源码和面试题(一)
在平时中集合使用中,当涉及多线程开发时,如果使用HashMap可能会导致死锁问题,使用HashTable效率又不高。而ConcurrentHashMap在保持同步同时并发效率比较高,ConcurrentHashmap是最好的选择,那面试中也会被常常问到,那可能的问题是:
367 0
面试:为了进阿里,死磕了ConcurrentHashMap源码和面试题(一)