reentrantreadwritelock通过将int型state变量高低16位分别存储读写状态实现锁复用:高16位(state>>>16)表示持有读锁的线程数,低16位(state&0xffff)表示写锁重入次数。

ReentrantReadWriteLock 用一个 int 类型的 state 变量 同时管理读锁和写锁的状态,核心就在于对这 32 位整数做高低 16 位的“按位拆分”——高 16 位存读状态,低 16 位存写状态,不额外引入字段,节省空间且保持 AQS 兼容性。
state 的位结构与提取方式
state 是 AQS 中唯一的同步状态字段,ReentrantReadWriteLock 没有新增变量,而是通过位运算复用它:
-
读状态(高 16 位):用
state >>> 16(无符号右移 16 位)获取,结果范围是 0~65535,表示当前持有读锁的线程总数(不是重入次数总和,而是不同线程个数,重入由 ThreadLocal 的 HoldCounter 单独记录) -
写状态(低 16 位):用
state & 0xFFFF(即state & ((1 )获取,结果范围也是 0~65535,表示当前持有写锁的线程的重入次数(同一线程可多次 lock,每次+1)
读锁与写锁如何共用同一个 state
读锁和写锁看似独立,但底层共享同一套 AQS 队列和同一 state 值,调度逻辑靠状态组合判断:
- 当
writeCount != 0(写状态非零),说明写锁被占用 → 所有新读请求必须等待(读写互斥) - 当
readCount != 0 && writeCount == 0,说明只有读锁被持有多次 → 新读请求可直接成功(读读共享) - 当
writeCount == 0 && readCount == 0,state 为 0 → 写请求可立即获取锁(空闲态) - 写锁重入时,只增加低 16 位;读锁获取时,只增加高 16 位;释放同理,各自减对应部分
为什么读锁重入不用 state 高位计数
因为多个线程可同时持读锁,仅靠高 16 位无法区分“谁重入了几次”。所以:
- state 高 16 位只记录持有读锁的线程数量(比如 3 个线程各持 1 次,高位值为 3)
- 每个线程自己的重入次数,由 ThreadLocal
维护,避免线程间干扰 - 这样既保证 state 轻量,又支持精确的 per-thread 重入控制
锁降级时 state 如何变化
锁降级指线程先持写锁、再获取读锁、最后释放写锁——整个过程 state 持续非零,但构成在变:
- 初始:写锁已占,state =
0x0000_0002(写重入 2 次) - 获取读锁后:state 变为
0x0001_0002(高 16 位 +1,低 16 位不变) - 释放写锁后:state 变为
0x0001_0000(低 16 位清零,高 16 位保留)→ 此时只剩读锁 - 该过程全程不出现 state == 0,所以其他写线程无法插入,保障数据一致性
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











