synchronized是粗粒度全互斥锁,所有读写操作均串行化;ReentrantReadWriteLock则按读写语义分离,允许多个读线程并发、读写/写写互斥,显著提升读多写少场景的吞吐量。
synchronized 和 reentrantreadwritelock 的核心差异不在“能不能互斥”,而在于“互斥的粒度和逻辑不同”:前者是粗粒度全互斥,后者按读写语义精细化分离。
读操作是否允许并发
synchronized 对所有访问(无论读或写)都强制串行化。哪怕只是 get() 一个值,也会阻塞其他线程的任何访问——包括另一个纯读请求。
ReentrantReadWriteLock 的 readLock() 是共享锁。多个线程可同时持有读锁,只要没有线程持有写锁。这在缓存读取、配置查询等高频只读场景下显著提升吞吐量。
- 典型场景:100 个线程并发读取 HashMap 数据 → synchronized 需排队执行;readLock() 可全部并行
- 注意:读锁不排斥读锁,但排斥写锁;写锁排斥一切(读/写)
写操作的互斥强度相同,但行为逻辑不同
两者对写操作都保证排他性:同一时刻最多一个线程能执行写逻辑。但关键区别在于“写操作发生时,读操作如何响应”:
- synchronized 下,写线程进入同步块后,后续所有读请求(无论是否已排队)必须等待该写完成
- ReentrantReadWriteLock 中,一旦有线程申请写锁,新来的读请求会被阻塞;已获取读锁的线程可继续执行,直到全部释放后,写锁才被授予
- 默认策略是非公平的,但可配置为写优先(避免读饥饿),也可通过 tryLock 控制等待行为
锁升级与资源开销
synchronized 在 JDK 1.6+ 后具备锁升级机制(偏向→轻量→重量),低竞争时开销极小,且由 JVM 自动管理生命周期。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
立即学习“Java免费学习笔记(深入)”;
ReentrantReadWriteLock 是显式锁,需手动 lock/unlock,且内部维护两把锁(ReadLock 和 WriteLock)及状态协调逻辑,内存占用和 CPU 调度开销略高。但它不依赖对象头 Mark Word,适用于更复杂的锁协作场景(如多条件等待、分段读写控制)。
- 简单临界区保护(如计数器增减)→ synchronized 更轻量、更安全
- 读远多于写的共享数据结构(如 ConcurrentMap 的底层实现、本地缓存)→ ReadWriteLock 更高效
可见性与内存语义一致
二者都遵循 JMM 的 happens-before 规则:锁释放前的写操作对后续获取同一锁的线程可见。因此在正确使用前提下,都能保证变量修改的可见性,无需额外加 volatile。
- synchronized 释放 monitor 时刷新主内存;readLock()/writeLock() 释放时同样插入内存屏障
- 不正确使用(如忘记 unlock、未在 finally 块中释放)会导致死锁或可见性失效,但这是使用问题,非机制缺陷

















