ReentrantReadWriteLock用一个32位state变量高16位存读锁次数、低16位存写锁重入次数,通过CAS原子更新;读锁共享允许多线程并发,写锁独占需无读无写方可获取,支持写锁降级但不可升级。

ReentrantReadWriteLock 通过分离读锁和写锁,让多个线程可以同时读、但写操作独占,从而提升并发读多写少场景下的吞吐量。它不是简单地用两个独立的锁,而是在一个同步器(AQS)实例上,用一个 int 类型的 state 变量同时管理读锁与写锁的状态。
读写状态如何共用一个 state
state 是一个 32 位整数:高 16 位表示读锁持有次数(共享锁),低 16 位表示写锁重入次数(独占锁)。例如:
- state = 0x00010002 → 读锁被获取了 1 次,写锁被获取了 2 次
- state = 0x00050000 → 5 个读线程同时持有读锁,无写锁
这种设计避免了额外对象开销,也保证了读写状态变更的原子性(靠 CAS 操作更新 state)。
读锁是共享锁,允许多个线程同时进入
当线程尝试获取读锁时,只要当前没有线程持有写锁(即低 16 位为 0),就允许成功,并将高 16 位加 1。多个读线程可并行执行,互不阻塞。
立即学习“Java免费学习笔记(深入)”;
- 读锁支持重入:同一线程多次 acquireRead(),高 16 位递增;对应次数 release() 后才真正释放
- 读锁不排斥其他读锁,但会阻塞写锁请求(写线程需等待所有读锁释放)
- 存在“写饥饿”风险:持续读请求可能导致写线程长期等待,可通过构造函数开启公平模式缓解
写锁是独占锁,完全互斥
写锁获取要求:state 的低 16 位为 0(无其他写锁),且高 16 位也为 0(无读锁)——即必须“无人读、无人写”才能成功。一旦获得,就独占访问权。
- 写锁支持重入:同一线程可重复获取,低 16 位计数递增
- 写锁释放后,若存在等待的读线程(非公平模式下可能优先唤醒写线程),会批量唤醒所有读线程
- 写锁可降级为读锁:持有写锁的线程在未释放写锁前,可直接获取读锁(此时 state 高低 16 位均非零),但读锁不能升级为写锁(会死锁)
实际使用注意事项
正确使用 ReentrantReadWriteLock 关键在于逻辑隔离和锁粒度控制:
- 只对真正共享且读多写少的数据结构加读写锁(如缓存 Map、配置快照)
- 读锁内不要调用可能升级为写操作的方法,避免隐式竞争
- 务必成对调用 lock()/unlock(),推荐用 try-finally 或 try-with-resources(配合自定义封装)
- 避免在读锁中执行耗时操作(如 I/O、远程调用),否则会拖慢所有后续写操作


















