读写分离锁的核心目的是让多个读线程真正并发执行,通过拆分读锁(共享锁,支持并发获取与计数管理)和写锁(独占锁,阻塞新读请求),实现读多场景高吞吐与一致性;禁止锁升级,需先释放读锁再获取写锁;公平性影响写线程饥饿与读性能。

读写分离锁的核心目的,就是让多个读线程能真正并发执行,而不是像普通互斥锁那样被迫排队——它通过把“读”和“写”拆成两把逻辑上独立、但状态联动的锁来实现这一点。
读锁是共享锁,天然支持并发
ReentrantReadWriteLock 的 readLock() 返回的是一个共享模式(Shared Mode)的锁。只要没有线程持有写锁,任意数量的线程都可以同时成功调用 lock() 获取读锁,不会阻塞彼此。这背后依赖 AQS 的共享队列机制,不是靠轮询或自旋抢锁,而是直接登记并允许并发进入。
- 多个读线程调用 readLock().lock() 时,只要写锁未被占用,全部立即成功
- 读锁计数器递增,AQS 内部维护当前持有读锁的线程数,而非独占 owner
- 释放读锁只是递减计数,仅当计数归零且存在等待写线程时,才唤醒写锁队列
写锁存在时,读锁自动阻塞
读写互斥不是靠读线程主动检查,而是由锁内部状态控制。一旦有线程成功获取 writeLock(),所有后续试图获取 readLock() 的线程会被挂入 AQS 的同步队列,直到写锁完全释放。这个过程对读线程透明,也不影响已持读锁的线程继续运行。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 写锁持有期间,新读请求不失败,而是阻塞等待——避免了“读操作因短暂写入而整体卡顿”的问题
- 已有读锁全部释放后,写锁才真正获得;写锁释放后,所有等待的读线程可批量唤醒并发执行
- 这种设计确保读多场景下吞吐量接近无锁,又不牺牲一致性
避免常见误用:别在读操作里嵌套写锁
读写锁不支持锁升级(即不能在持有读锁时再去获取写锁),否则会死锁。如果业务需要“先读后写”,应明确分两步:先释放读锁,再申请写锁。
- 错误示范:readLock.lock(); ... if (needUpdate) writeLock.lock(); → 必然阻塞甚至死锁
- 正确做法:读完判断需更新 → unlock readLock → lock writeLock → 执行写 → unlock
- 若需保证“读之后立刻写”的原子性,说明场景不适合读写锁,应回退到 ReentrantLock 或其他方案
公平性与性能取舍要结合场景
ReentrantReadWriteLock 默认是非公平模式,读线程可能持续抢占,导致写线程饥饿;启用公平模式(构造时传 true)可按 FIFO 调度,但会降低读吞吐。是否开启,取决于写操作的实时性要求。
- 缓存读取、配置查询等纯读密集型场景,非公平模式更高效
- 配置热更新、状态快照保存等写操作不可长期延迟的场景,建议设为公平
- 可通过 getReadHoldCount() 和 getWriteHoldCount() 实时监控锁持有情况,辅助调优
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










