ReentrantReadWriteLock用32位state高16位存读锁线程数、低16位存写锁重入数,因AQS仅提供单个state字段,位切分可原子更新且避免额外同步开销;读锁并发允许高16位累加,写锁独占要求低16位为0且高16位为0。

ReentrantReadWriteLock 用一个 int 类型的 state 变量同时管理读锁和写锁的状态,关键就在于把这 32 位整数“一分为二”:高 16 位管读,低 16 位管写。
为什么必须这样切分?
因为 AQS 只提供一个 state 字段,而读写锁需要独立记录两件事:
- 有多少个线程正在读(读锁被多少线程持有,是共享计数)
- 当前写锁被同一个线程重入了几次(写锁的独占重入次数)
如果另起变量或加锁同步来维护这两个值,会引入额外开销、破坏原子性。位切分让一次 volatile 写 + 位运算就能完成状态更新,高效且线程安全。
高 16 位怎么表示读锁状态?
高 16 位(bit 16–31)存储的是持有读锁的线程总数,不是每个线程的重入次数总和,而是“有多少个不同线程获取了读锁”。
立即学习“Java免费学习笔记(深入)”;
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- 每次有新线程成功加读锁,state 就加 0x00010000(即 1
- 读锁释放时,对应减去这个单位值
- 获取当前读锁线程数:用 state >>> 16(无符号右移 16 位)
注意:单个线程多次重入读锁,不会重复增加高 16 位;它靠 ThreadLocal 的 HoldCounter 单独记录本线程的重入次数,避免干扰全局计数。
低 16 位怎么表示写锁状态?
低 16 位(bit 0–15)只服务写锁,记录当前持有写锁的线程的重入次数。
- 首次获取写锁:低 16 位从 0 变为 1
- 同一线程再次 lock():+1;unlock() 一次:−1;归零才真正释放
- 提取写锁重入数:用 state & 0xFFFF(即 state & EXCLUSIVE_MASK)
写锁获取的前提是:低 16 位为 0(无人持写锁)且 高 16 位也为 0(无人在读)——确保写操作绝对独占。
读锁能并发进入的关键条件
读锁不看高 16 位是否为 0,只检查低 16 位是否为 0(即写锁空闲)。只要没线程在写,多个线程就能同时成功加读锁,各自推动高 16 位递增。
- 读+读 → ✅ 允许(高 16 位累加)
- 读+写 → ❌ 互斥(读时写被阻塞,写时读被阻塞)
- 写+写 → ❌ 互斥(低 16 位非零时,其他写线程获取失败)
这种设计直击“读多写少”场景痛点:读操作不争抢、不阻塞彼此,仅与写操作保持严格互斥。

















