这玩意比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

目录
相关文章
|
Dubbo Cloud Native 网络协议
【Dubbo3技术专题】「服务架构体系」第一章之Dubbo3新特性要点之RPC协议分析介绍
【Dubbo3技术专题】「服务架构体系」第一章之Dubbo3新特性要点之RPC协议分析介绍
352 1
|
存储 Python
【可定制、转换时间戳】解析nc文件,并保存为csv文件
【可定制、转换时间戳】解析nc文件,并保存为csv文件
924 4
|
11月前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
12月前
|
运维 Cloud Native Java
热联集团:从 APISIX 迁移到云原生网关
我们将核心业务系统从 IDC 全栈迁移到阿里云后,并采用了云原生 API 网关,通过其独有的软硬一体的加速方案,相比普通 HTTPS 请求 TLS 握手时延降低一倍,极限 QPS 提升 80% 以上,运维效率也提升了 50%,此外,我们把 Nacos 迁移到 MSE Nacos,稳定性、性能和运维成本等方面都具备了明显的优势。
|
消息中间件 缓存 中间件
缓存一致性问题,这么回答肯定没毛病!
缓存一致性问题,这么回答肯定没毛病!
241 3
|
机器学习/深度学习 Python
深入了解CatBoost:自定义目标函数与度量的高级教程
深入了解CatBoost:自定义目标函数与度量的高级教程【2月更文挑战第18天】
686 1
|
编解码 Dubbo NoSQL
由浅入深理解RPC架构设计
🌴🌴经常听到大家说不同项目之间调用使用HTTP方式,同一个项目内不同服务之间调用使用RPC方式。今天就来学习一下`RPC框架`,RPC框架由哪些部分组成又是如何一步一步设计出来的。
900 0
由浅入深理解RPC架构设计
520专属——使用Python代码表白究竟能不能成功?
520,谐音:“我爱你”,一直觉得,520真正的意义,不单是用于表达爱,也不是为了收礼物和红包,而是提醒我们,不要忘记爱与被爱。 废话不多说,下面整理了9个效果图和参考代码,感兴趣的朋友可以看看
正则表达式高级用法
正则表达式是强大的文本匹配工具,常用于搜索、匹配和验证字符串。高级用法包括:捕获组(区分需要提取的内容)、非捕获组(减少开销)、零宽断言(定位匹配位置)、反向引用(匹配相同内容)、嵌入代码(实现复杂逻辑)、贪婪与非贪婪匹配(控制匹配范围)和递归匹配(处理嵌套结构)。了解这些高级技巧能提升字符串操作效率。示例展示了验证Email、电话号码、提取URL和清理多余空格的正则表达式应用。