
ReadWriteLock 为什么不能直接 new?
Java 里没有 ReadWriteLock 的具体实现类可直接 new,它只是个接口。你真正要用的是 ReentrantReadWriteLock —— 这是 JDK 提供的唯一标准实现,也是绝大多数场景下的唯一选择。
常见错误是写成:new ReadWriteLock(),编译直接报错;或者误以为 StampedLock 是它的子类(其实不是,它是独立设计,API 和语义都不同)。
- 必须用
new ReentrantReadWriteLock()实例化 - 构造支持传
boolean参数:设为true启用公平模式(写线程优先获取锁),但会显著降低吞吐量,读多写少时通常保持默认false - 公平模式下,即使只有读线程在等,新来的写线程也会插队,反而让读饥饿——这和直觉相反,得小心
读锁和写锁必须配对 unlock(),且不能跨线程
ReentrantReadWriteLock 的读锁和写锁都支持重入,但释放必须由**同一线程**完成,且 lock() 和 unlock() 必须严格配对。漏掉 unlock() 不会立刻报错,而是导致其他线程永久阻塞。
典型翻车现场:在 try 里 lock(),但把 unlock() 写在 finally 外面;或用 return 提前退出,跳过了释放逻辑。
- 读锁和写锁的
unlock()不能混用:拿读锁必须用readLock().unlock(),写锁同理 - 不要在 lambda 或异步回调里释放锁——线程变了,
unlock()会抛IllegalMonitorStateException - 建议用 try-with-resources 包一层(需自行封装
AutoCloseable),比裸写finally更可靠
读锁不互斥,但会阻塞写锁 —— 注意“写饥饿”风险
多个读线程可以同时持有读锁,这是提升并发读性能的关键。但只要有一个读锁没释放,所有写线程就卡在 writeLock().lock() 上。如果读操作频繁、耗时长(比如读大对象、IO 等待),写线程可能一直等不到机会。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
这不是 bug,是设计使然。但业务上常被忽略:比如缓存刷新(写)总被查缓存(读)压着,导致数据长期不更新。
- 避免在读锁内做耗时操作,尤其是网络调用、数据库查询、大对象拷贝
- 考虑降级策略:给写锁加超时(
writeLock().tryLock(1, TimeUnit.SECONDS)),失败则走补偿流程 - 如果写操作也频繁,说明已不满足“读多写少”前提,
ReadWriteLock反而比普通synchronized更慢(锁开销更大)
和 synchronized 比,什么情况下反而更慢?
ReentrantReadWriteLock 的锁管理比 synchronized 重得多:要维护读写状态计数、线程队列、唤醒逻辑。当读操作本身极轻(比如只读几个字段)、且竞争极少时,它带来的额外开销可能超过收益。
简单测过:单线程反复读一个 int 字段,用 ReentrantReadWriteLock 比 synchronized 慢 2–3 倍;但 10 个线程并发读,差距就反转了。
- 别为了“看起来高级”而用——先确认真实瓶颈在读竞争,而不是 CPU 或 GC
- 注意 JVM 对
synchronized的优化(偏向锁、轻量级锁),在低争用下非常高效 - 如果读写比例接近 1:1,或写操作占比超 20%,基本不用考虑它
真正难的不是怎么写那几行 lock() 和 unlock(),而是判断此刻要不要用它、以及用的时候有没有悄悄把读操作拖慢到让写线程饿死。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










