ReentrantReadWriteLock通过分离读写锁提升并发性能:读锁共享允许多线程并发读,写锁独占确保写操作互斥;支持锁降级但不支持升级;需在finally中释放锁,可选公平/非公平模式。

ReentrantReadWriteLock 通过分离读写操作的锁,让多个线程可以同时读、但写时独占,从而显著提升读多写少场景下的并发性能。
读写锁的核心分工:读锁共享,写锁互斥
它内部维护一对锁:ReadLock 和 WriteLock。读锁是可重入、共享的——只要没有写锁在持有,任意数量的读线程都能同时进入临界区;写锁则是可重入、排他的——同一时刻最多只有一个写线程能获取,且会阻塞所有读锁请求。这种设计天然适配“读远多于写”的业务,比如缓存查询、配置加载、报表统计等。
- 读操作用
readLock().lock()获取,完成后必须调用unlock() - 写操作用
writeLock().lock()获取,同样需配对解锁 - 不能在持有读锁时直接升级为写锁(会死锁),需先释放读锁再申请写锁
正确使用锁的典型结构:try-finally 保障解锁
忘记释放锁会导致线程永久阻塞,所以务必用 try-finally 包裹临界区。读写锁不支持 lockInterruptibly 的中断语义(除非显式启用公平策略),但基础安全仍是底线。
- 读操作示例:
rwLock.readLock().lock();
try {
return data.get(key); // 安全读取
} finally {
rwLock.readLock().unlock();
}
- 写操作示例:
rwLock.writeLock().lock();
try {
data.put(key, value); // 安全更新
} finally {
rwLock.writeLock().unlock();
}
注意锁降级:写锁 → 读锁 是唯一允许的升级路径
ReentrantReadWriteLock 支持锁降级(downgrading):即在持有写锁期间获取读锁,然后释放写锁,从而继续以读锁保护数据——这能避免写完立刻读时的重复加锁开销和潜在竞态。但反过来(读锁→写锁)绝对禁止,会引发死锁。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
立即学习“Java免费学习笔记(深入)”;
- 降级写法要点:必须在同一个线程内,先获取写锁,再获取读锁,最后释放写锁
- 不推荐在读锁未释放时尝试获取写锁,应设计为先释放读锁再争抢写锁
- 若需“读-改-写”逻辑,优先考虑是否能用 CAS 或更轻量的同步机制替代
选择公平性策略:吞吐 vs 响应性
构造时可传入 boolean fair 参数。非公平模式(默认)吞吐更高,但可能饿死长等待线程;公平模式按 FIFO 调度,响应更可预测,适合写操作频繁或对延迟敏感的场景。
- 高并发读场景通常用默认非公平,减少上下文切换开销
- 写操作较重或存在明显长任务时,可启用公平策略防止个别写线程被无限推迟
- 公平锁会带来额外同步开销,实测 QPS 下降约 5%~10%,需权衡
不复杂但容易忽略:锁粒度要匹配业务边界,别把整个 Map 用一把读写锁保护,而应按 key 分段或结合 ConcurrentHashMap 提升伸缩性。

















