ReentrantReadWriteLock禁止锁升级,因AQS校验到线程已持读锁时会直接拒绝写锁获取并无限park,导致死锁;安全做法是用tryLock()替代lock(),或采用锁降级保障可见性。
Java 中 ReentrantReadWriteLock 不允许锁升级,即线程在持有读锁(ReadLock)的情况下,调用写锁(WriteLock)的 lock() 方法会永久阻塞,形成死锁表象。这不是 bug,而是明确的设计约束。
核心在于 AQS 的状态校验逻辑:当线程已持读锁时,writeLock.lock() 会先检查是否有其他写锁占用;确认无竞争后,立即检查「当前线程是否已持读锁」——结果为真,便直接拒绝获取写锁,并将线程加入 AQS 队列无限 park。
缓存加载中常见的「读-判断-写」链极易触发该问题:
readLock.lock() 查询缓存writeLock.lock()
这种写法在高并发下无法靠超时或重试缓解,因为 lock() 是无条件阻塞,失败路径根本不存在。
立即学习“Java免费学习笔记(深入)”;
真正可落地的协调逻辑必须绕开「持读锁再抢写锁」路径:
writeLock.tryLock(100, TimeUnit.MILLISECONDS) 尝试抢占写锁;成功则双检写入,失败则退避或 fallbackreadLock.tryLock() 非阻塞获取;失败立即重试或让出 CPU,绝不调用 lock()
锁降级的唯一正当用途,是保障「写后立刻读」的数据可见性——写锁释放前先获取读锁,确保后续读操作看到刚写入的最新值。
tryLock() 的失败处理