源码级丨从 jdk 的 git 提交记录告诉你 AQS 读写锁 为什么需要特意维护 firstReader 和 cacheHoldCounter

源码篇 预防针💉:

源码篇 必然会有很多代码,希望大家不要有畏难情绪,虽然我也是看到一大串代码就头疼。 我贴代码只是为了方便我的文字解答,源码只是辅助我文字讲解,所以大家尽量关注我的文字就好啦。

前言

在上一篇文章中,我们得知了 ReentrantReadWriteLock 给每个线程都维护了一个 ThreadLocal 类型的 HoldCount 对象,用来维护每个线程的读锁重入次数。

然后我留下了一些疑问:

  • 为什么每个线程都维护了 HoldCounter,还需要额外维护一个 firstReader ?

  • 为什么需要特意维护 CacheHoldCounter?

为什么需要特意维护 firstReader 和 cacheHoldCount

为什么 ReentrantReadWriteLock 特意维护了 第一个线程 和 最后一个 获取锁成功的线程?

只维护头和尾能带来性能上的提升吗?具体体现在哪里?

ThreadLocal 的查询

我们先来看 为什么需要 cacheHoldCount

在源码 fullTryAcquireShared 方法中其实我们可以看到有这么一个注释:

显然 cacheHoldCounter 是为了 释放锁 而特意维护的。

那 cacheHoldCounter 究竟能帮助我们怎么去优化 释放锁 呢?

看到这里基本上就是真相大白了。

cachedHoldCounter 是用来优化 锁释放时 的 ThreadLocal 查找的。

而且这里提到了一个普遍的例子就是:通常来说需要释放的线程,就是最后一个获取锁的线程。

在这种场景下,我们就不需要去通过 ThreadLocal 去查,而是直接通过我们这个 cacheHoldCounter。

那为什么需要维护 firstReader 捏?

通过注释其实是不太好找到线索的。

但是我们可以先确定的一件事就是,firstReader 肯定能起到跟 cachHoldCounter 的作用,也就是在优化了在 ThreadLocal 的查找。

tryReleaseShared 读锁释放逻辑:

ThreadLocal 的内存溢出风险

我们通过 jdk 的 git 历史提交记录可以看到,这个 firstReader 其实是后来才加进来的。

Excessive ThreadLocal storage used by ReentrantReadWriteLock。

大概意思就是:ReentrantReadWriteLock 用 ThreadLocal 太多了。

ThreadLocal 虽然是一个好东西,但是它有一个非常大的问题就是它存在 内存溢出 的风险。

现在多加了一个 firstReader,相当于是一把 ReentrantReadWriteLock 就优化一个 ThreadLocal 变量。

积少成多,也是对性能比较极致的追求。

而且我们还可以看到这个提交记录中还包括了对锁中的 ThreadLocal 对象手动清除: readHolds.remove()。

这属于是一个 bug,也是在这次提交中修复了。

感兴趣的大兄弟可以去具体 oracle 官网查看:Bug ID: JDK-6625723 Excessive ThreadLocal storage used by ReentrantReadWriteLock (java.com)

总结

为什么需要 cacheHoldCounter ?

cacheHoldCounter 是维护最后一个成功获取到锁的线程。

维护它是为了在 锁释放 中减少对于 ThreadLocal 的查询。

为什么需要 firstReader ?

目的是为了优化 读写锁 中对 ThreadLocal 的过度使用导致内存溢出问题。

在早期设计 读写锁 中是没有 firstReader,后来人们提出他对于 ThreadLocal 的使用已经达到了 滥用 这个级别。

但是又不得不用 ThreadLocal,所以 Doug Lea 采用了维护一个 firstReader 的方法,尽可能地去减少这个内存的占用。

同时 fistReader 在 锁释放 的时候也可以优化 ThreadLocal 的查询。

参考

来都来了,点个赞,留个言再走吧彦祖👍,这对我来说非常重要!

相关推荐
小羊没烦恼!3 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
俊昭喜喜里3 天前
java中的继承和多态的区别
java
小羊没烦恼!3 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
譕痕3 天前
JSONObject与JSONArray封装数据格式区别
java·json
胡写代码3 天前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖3 天前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时3 天前
01-06-A-JVM排查实战详解
java·jvm
晨米酱3 天前
AGENTS.md:Agent 的上下文策略层
面试·架构·agent
vipxieliang3 天前
ValidX 在 DDD 领域驱动设计中的实践
java·spring boot
ba_pi3 天前
mysql 查询所有表名并授权
java