最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Java 中 ReentrantReadWriteLock 锁升级是否允许及其原因
时间:2026-07-27 18:34:53 编辑:袖梨 来源:一聚教程网
ReentrantReadWriteLock禁止锁升级,因AQS校验到线程已持读锁时会直接拒绝写锁获取并无限park,导致死锁;安全做法是用tryLock()替代lock(),或采用锁降级保障可见性。
Java 中 ReentrantReadWriteLock 不允许锁升级,即线程在持有读锁(ReadLock)的情况下,调用写锁(WriteLock)的 lock() 方法会永久阻塞,形成死锁表象。这不是 bug,而是明确的设计约束。
为什么锁升级被禁止
核心在于 AQS 的状态校验逻辑:当线程已持读锁时,writeLock.lock() 会先检查是否有其他写锁占用;确认无竞争后,立即检查「当前线程是否已持读锁」——结果为真,便直接拒绝获取写锁,并将线程加入 AQS 队列无限 park。
- 读锁未释放,写锁又无法获取,线程卡在 WAITING(parking) 状态
- 其他线程也无法获取写锁(因读锁仍存在),且新读请求也会被阻塞(写锁已在排队)
- 单一线程“半占”锁资源,导致整个读写锁系统陷入全局阻塞
典型错误代码模式
缓存加载中常见的「读-判断-写」链极易触发该问题:
- 先
readLock.lock()查询缓存 - 发现 miss,不释放读锁,直接调用
writeLock.lock() - 多个并发线程同时卡在同一行,服务逐渐夯死
这种写法在高并发下无法靠超时或重试缓解,因为 lock() 是无条件阻塞,失败路径根本不存在。
立即学习“Java免费学习笔记(深入)”;
唯一安全的替代方式是 tryLock()
真正可落地的协调逻辑必须绕开「持读锁再抢写锁」路径:
- 优先用
writeLock.tryLock(100, TimeUnit.MILLISECONDS)尝试抢占写锁;成功则双检写入,失败则退避或 fallback - 若必须走读优先路径,只能用
readLock.tryLock()非阻塞获取;失败立即重试或让出 CPU,绝不调用lock() - 锁降级仅适用于「已稳持写锁 → 获取读锁 → 释放写锁」这一单向流程,且不能混入异常、异步或定时逻辑
锁降级不是为了省开销,而是保可见性
锁降级的唯一正当用途,是保障「写后立刻读」的数据可见性——写锁释放前先获取读锁,确保后续读操作看到刚写入的最新值。
- 把它当成通用流程嵌套进 if/else 或 try/catch,极易遗漏
tryLock()的失败处理 - 一旦失败路径覆盖不全,不如统一用写锁兜底:逻辑更清晰,风险更可控
相关文章
- AI也唤不醒“乏力”的618 08-16
- Kimi Work 迎重大升级:推出“目标模式”并打通外部应用插件 08-16
- 起跑线还没过呢,香槟就开了 08-16
- 出海短剧大洗牌:8成消耗流向AI短剧,实拍项目锐减50% 08-16
- 基于多Agent系统自动发现科学假设 08-16
- 一个合格的AI面试官,需要解决企业招聘哪些问题? 08-16