根本原因在于读写互斥的设计原则和AQS状态管理机制:只要写锁被持有(state低16位非零),读锁获取逻辑便直接拒绝新读请求,不入队、不重试,确保数据一致性。

写锁申请会阻塞后续读锁,根本原因在于读写互斥的设计原则和 AQS 状态管理机制。
读写互斥的硬性规则
ReentrantReadWriteLock 明确规定:只要存在一个线程持有写锁,任何其他线程(无论读或写)都无法获取锁。这不是“优先级”问题,而是状态层面的禁止:
- 写锁独占意味着 当前 state 的低16位非零(即写锁计数 > 0)
- 读锁获取逻辑会先检查:若写锁已被占用(state & 0xFFFF ≠ 0),直接拒绝,不进入排队或重试
- 即使队列中已有读线程在等,新来的读线程也会被拦截,不会入队
AQS 同步器的判断逻辑
读锁的 tryAcquireShared 方法内部有关键判断:
- 先读取当前 state 值
- 若低16位(写锁部分)不为 0 → 直接返回 -1(表示获取失败)
- 该判断发生在任何队列操作之前,属于快速失败路径
- 因此,写锁一旦被持有,所有新读请求立刻被挡在门外,不产生额外同步开销
公平与非公平策略的影响
是否“立即阻塞”还取决于构造时是否启用公平模式:
立即学习“Java免费学习笔记(深入)”;
- 非公平模式(默认):新读线程可能尝试抢占,但只要写锁存在,抢占必然失败,仍需等待
- 公平模式:新读线程直接加入 AQS 队列尾部,等待写锁释放后被唤醒;此时它已处于阻塞状态
- 无论哪种模式,只要写锁没释放,读锁就无法成功 acquire
为什么不能让读锁“绕过”写锁?
这是数据一致性的底线要求:
- 写操作可能修改共享状态,若允许读线程在写进行中读取,会导致脏读、部分更新等严重问题
- 例如:缓存正在刷新一半,另一个线程读到的是旧值+新值混杂的中间态
- 阻塞读锁不是性能妥协,而是语义安全的强制保障


















