reentrantreadwritelock仅在读多写少场景下有效,需严格控制锁范围、避免锁升级、慎用公平模式。适用元数据缓存等场景,不适用于高频更新或重读操作。

ReentrantReadWriteLock 本身不自动减少锁竞争,它只是提供了一种读写分离的机制。真正起作用的是你如何用它——关键在场景匹配、使用方式和边界控制。
只在读多写少时才真正有效
它的设计前提是读操作远多于写操作(比如缓存读取、配置查询)。如果写操作频繁(例如每秒上百次更新),写锁的独占性会让所有读线程排队等待,吞吐反而比普通 ReentrantLock 还低。更糟的是,一旦读操作本身很重(比如遍历大 Map 或序列化整个对象),读锁的“并发优势”也会被抵消。
- 典型适用场景:元数据缓存、静态配置中心、只读报表服务
- 慎用场景:高频更新的计数器、实时状态同步、带复杂计算的读逻辑
读锁不能升级为写锁,避免死锁陷阱
ReentrantReadWriteLock 不支持锁升级。如果一个线程先持有读锁,再尝试获取写锁,会永远阻塞——因为写锁要求所有读锁释放,而它自己正占着读锁。这是常见死锁源头。
- 正确做法:需要“先读再写”的逻辑,必须提前释放读锁,再申请写锁
- 替代方案:改用 StampedLock 的乐观读 + validate 机制,更适合低冲突、高响应要求的场景
锁范围必须严格对齐共享状态修改边界
很多人把整个业务方法包进读锁或写锁里,结果读操作中混入了日志打印、远程调用、JSON 序列化等耗时动作,导致读锁持有时间过长,大量线程卡在 readLock().lock() 上。
- 只把真正访问/修改共享变量的代码放进锁块
- 读操作中避免 I/O、网络请求、复杂计算;写操作中避免冗余校验或非必要赋值
- 示例:读取 configMap.get("timeout") 是安全的;但 configMap.get("timeout").toString() + "ms" 后续拼接应移出锁外
公平策略不是性能优化,而是调度保障
开启公平模式(new ReentrantReadWriteLock(true))会让线程按到达顺序排队,避免饥饿,但会显著降低吞吐量。默认非公平模式在大多数场景下更高效。
- 仅在写线程长期得不到执行、出现明显饥饿时才考虑公平模式
- 公平锁增加上下文切换和队列管理开销,高并发下延迟波动更大
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











