ReentrantReadWriteLock通过位拆分state实现读写锁:低16位存写锁重入次数,高16位存持有读锁的不同线程数;写锁抢占需无读锁且写锁未被其他线程持有,读锁获取需无写锁或写锁为当前线程。

ReentrantReadWriteLock 的 ReadLock 和 WriteLock 共享同一个 AQS state,靠的是对 int 类型 state 的**位拆分设计**:低 16 位表示写锁重入次数,高 16 位表示持有读锁的线程数(注意不是读锁重入总次数,而是不同线程获取读锁的计数)。
state 的位划分与含义
AQS 的 state 是一个 32 位 int。ReentrantReadWriteLock 将其拆成两部分:
- 低 16 位(0~65535):代表写锁的重入计数。写锁是独占锁,同一时刻最多一个线程持有,所以只需记录该线程重入了多少次。
- 高 16 位(65536~4294967295):代表当前持有读锁的线程个数(即成功调用 readLock().lock() 且尚未 unlock 的不同线程数量)。注意:同一个线程可多次获取读锁(支持重入),但高 16 位不直接记录该线程的重入次数——这部分由 ReadLock 自己维护(通过 ThreadLocalHoldCounter)。
写锁如何操作 state
WriteLock 在 tryAcquire 中做以下判断和更新:
- 先用
getState() & 0xFFFF取出低 16 位,若非 0,说明已有线程持有写锁;再检查是否是当前线程——是则允许重入,state + 1;否则失败。 - 若低 16 位为 0,还需确保高 16 位也为 0(即无读锁持有者),否则写锁无法抢占(体现“写优先”或“写阻塞读”的公平性逻辑)。
- 成功时,用 CAS 更新 state:原值 + 1(仅低 16 位加 1,高位不变)。
读锁如何操作 state
ReadLock 在 tryAcquireShared 中处理更复杂:
立即学习“Java免费学习笔记(深入)”;
- 先读取当前 state,分离高低位:
int c = getState(); int r = c >> 16;(r 即当前读锁线程数)。 - 检查写锁是否被占用:
c & 0xFFFF != 0且持有者不是当前线程 → 直接失败(写锁存在且非本线程,读锁不能获取)。 - 计算新 state:
nextc = c + (1 (即高位 +1),再 CAS 更新。但 CAS 失败会重试。 - 真正记录每个线程读锁重入次数,靠的是内部类
HoldCounter和ThreadLocalHoldCounter,不依赖 state 高位——高位只统计“有几个线程正在持有读锁”。
为什么这样设计?
这种拆分兼顾了效率与语义清晰:
- 避免为读写锁分别维护两个 state 变量,节省内存和同步开销。
- 高位计数能快速判断是否有读锁持有者(用于写锁抢占决策),低位能精确控制写锁重入。
- 读锁重入细节交给线程局部变量管理,既支持可重入,又不污染全局 state 语义。


















