ReadWriteLock 通过分化锁粒度实现读并发、写独占,提升读多写少场景吞吐量,但不涉及数据或服务的物理分离;其核心是读读不互斥、读写互斥、写写互斥,支持写锁降级但禁止读锁升级;正确使用需严格配对 lock/unlock、避免读操作含副作用、写占比超10%~15%时应换方案。

ReadWriteLock 本身不“实现读写分离”这个架构模式,而是通过锁粒度的分化,在同一份共享数据上支持读并发、写独占,从而在读多写少场景下提升吞吐量。它优化的是访问控制逻辑,不是数据或服务层面的物理分离。
读写锁的核心行为机制
ReentrantReadWriteLock 维护一对逻辑锁,共享同一同步状态:
- 多个线程可同时获取 readLock(),只要没有线程持有 writeLock
- writeLock() 是排他锁:获取时要求既无其他写锁,也无任何读锁在持有中
- 读读不互斥、读写互斥、写写互斥——这是并发收益的来源
- 支持写锁降级(先持写锁,再获取读锁,再释放写锁),但禁止读锁升级(否则死锁)
正确使用的三个关键实操点
很多性能问题源于用法偏差,而非锁本身:
- 必须严格配对 lock/unlock:readLock().lock() 只能由 readLock().unlock() 释放;writeLock 同理。Java 不校验类型,误用会导致永久阻塞
- 读操作里不能藏副作用:读锁只保护对共享对象的读取动作。DB 查询、RPC 调用、日志打印、构造新对象等都应移出 readLock 块,否则拖长读锁持有时间,卡住所有写线程
- 写占比超 10%~15% 就该换方案:ReadWriteLock 的 CAS 和内存屏障开销比 synchronized 大。高写频下反而更慢,此时回归 synchronized 或 ReentrantLock 更稳
典型误用与替代建议
不是所有“读多写少”都适合 ReadWriteLock:
立即学习“Java免费学习笔记(深入)”;
- 已用 ConcurrentHashMap、CopyOnWriteArrayList 等线程安全容器,外层再套 ReadWriteLock 属于冗余加锁,纯增开销
- 读操作极轻量(如读一个 volatile int 字段),加锁反而成为瓶颈
- 业务允许弱一致性(如缓存容忍短暂脏读),StampedLock 的乐观读可能更高效
- 需要真正“读写分离”的架构(比如主库写、从库读),那是数据源或服务层的事,不是 ReadWriteLock 的职责
一个干净的缓存示例
以下结构体现最小必要封装和责任边界:
private final Map<String, Object> cache = new HashMap<>();
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock readLock = lock.readLock();
private final Lock writeLock = lock.writeLock();
public Object get(String key) {
readLock.lock();
try {
return cache.get(key); // 仅读共享map,无IO、无赋值、无副作用
} finally {
readLock.unlock();
}
}
public Object put(String key, Object value) {
writeLock.lock();
try {
return cache.put(key, value); // 仅写共享map
} finally {
writeLock.unlock();
}
}
不复杂但容易忽略



















