reentrantlock与synchronized在jdk17+下性能差距大幅收窄,低竞争时synchronized占优,中等竞争差距±15%,高竞争时reentrantlock更稳定;选型应基于真实业务场景的竞争强度、临界区行为及工程约束,而非单纯理论或空循环测试。

评估 ReentrantLock 与 synchronized 的性能差异,不能只看理论或单次测试,关键在于贴合真实业务场景的多维度实测。现代 JVM(JDK 17+)下二者差距已大幅收窄,但选型仍需依据具体竞争模式、临界区行为和工程约束来判断。
明确测试前提:避免无效对比
直接跑一个空循环加锁测耗时,结果毫无参考价值。有效评估必须满足:
- 使用 JDK 17 或更高版本(偏向锁默认禁用,轻量级锁策略更成熟)
- 关闭 JMX 和过多诊断参数,避免干扰 JIT 编译和锁优化
- 预热足够轮次(通常 ≥5 分钟),让 JIT 稳定编译并触发锁状态调整
- 控制变量:相同临界区逻辑、相同线程数、相同 GC 设置(建议 G1,停顿可控)
按竞争强度分层设计压测
二者性能表现高度依赖线程争抢程度,应分三类典型场景单独验证:
- 低竞争(单线程反复进入):synchronized 占优。JVM 在无竞争时将锁维持在轻量级状态,monitorenter 开销极小;ReentrantLock 每次 lock()/unlock() 都需 CAS 更新 state、检查中断标志、维护 AQS 节点,固定开销更高
- 中等竞争(2–8 线程交替争抢):差距最小。synchronized 可能自旋成功,ReentrantLock 的队列调度也较高效,实测吞吐量差异常在 ±15% 内
- 高竞争(≥16 线程高频争抢):ReentrantLock 更稳定。synchronized 升级为重量级锁后依赖 OS 互斥量,涉及内核态切换;ReentrantLock 虽同样阻塞,但唤醒逻辑在 Java 层可控,且 tryLock(timeout) 可主动退避,避免雪崩式排队
关注真正影响性能的工程细节
锁类型本身不是瓶颈主因,以下因素往往起决定性作用:
- 临界区大小:若同步块内含 IO、远程调用或复杂计算,锁开销占比微乎其微,换锁无意义
- 锁粒度:一把大锁保护整个对象,远比细粒度分段锁慢——这与选用哪种锁无关
- 虚假共享(False Sharing):多个线程频繁修改同一缓存行中的不同 volatile 字段,会显著拖慢 ReentrantLock 的 state CAS 和 synchronized 的 Mark Word 更新
- 异常路径频率:synchronized 在异常时自动释放锁;ReentrantLock 若未严格写在 finally 中,可能造成死锁,间接导致性能恶化
推荐验证方式:用 JMH + Arthas 定量观察
不靠 System.nanoTime() 手动计时,而是:
- 用 JMH 编写参数化基准测试,固定线程组数(@Fork、@Threads)、测量 mode(Throughput / AverageTime)
- 运行时用 Arthas 的 trace 命令观察 monitorenter / AbstractQueuedSynchronizer.acquire 的实际耗时分布
- 通过 JVM 参数 -XX:+PrintGCDetails -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly(需 hsdis)辅助分析锁升级是否发生、是否进入重量级状态
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











