JDK 15默认禁用偏向锁后单线程高频synchronized块性能无显著下降,因轻量级锁在无竞争时开销极低,且JIT可通过内联、逃逸分析实现锁消除或降为纯分支判断,完全规避CAS重复执行与内核态切换。

JDK 15 默认禁用偏向锁后,单线程高频 synchronized 块的执行损耗不会显著上升——因为轻量级锁在无竞争时的开销已非常接近无锁,且 JIT 编译器会进一步优化掉冗余同步。
为什么单线程场景下看不到明显性能下降?
禁用偏向锁(-XX:-UseBiasedLocking)后,对象初始状态直接跳过偏向锁,进入「无锁 → 轻量级锁」路径。而单线程反复进入同一同步块时:
- 第一次进入:通过 CAS 将当前线程 ID 写入对象头
Mark Word,成功即获得轻量级锁 —— 这是一次原子操作,现代 CPU 上耗时通常在 10–30 纳秒 - 后续进入:仍需比对线程 ID 并验证锁状态,但无需再次 CAS;JIT 在稳定编译后可能内联该判断,甚至结合逃逸分析做锁消除(
Lock Elimination) - 没有其他线程竞争,就不会触发自旋或升级到重量级锁,完全规避了系统调用和内核态切换
如何验证实际损耗是否被 JIT 消除?
不能只看字节码或简单微基准测试,必须观察运行时真实行为:
- 添加 JVM 参数:
-XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:+LogCompilation,检查同步方法是否被 C2 编译器内联或消除 - 用 JMH 写对比测试时,确保
@Fork足够多轮次(如@Fork(jvmArgs = {"-XX:-UseBiasedLocking"})),避免预热不充分导致轻量级锁未稳定 - 关键指标不是“每次同步耗时”,而是
perf stat -e cycles,instructions,cache-misses下的底层事件 —— 若指令数/周期数与等效非同步代码接近,说明锁已被消除或降为纯分支判断
哪些情况会让损耗“突然可见”?
真正暴露轻量级锁开销的,不是单线程本身,而是它破坏了原本可被消除的条件:
- 对象逃逸:同步对象被传递到其他线程作用域(哪怕只是日志打印、放入集合),JIT 不敢做锁消除,每次进入都强制走轻量级锁流程
- 频繁哈希计算:若对象在同步前调用过
hashCode()(且未覆写),Mark Word中已存 hash 值,轻量级锁无法复用该字段,会退化为更重的锁结构校验逻辑 - 短生命周期对象:每 new 一个新对象再同步,无法复用上次的锁状态,每次都走完整轻量级锁获取路径,CAS + 内存屏障成本累积可见
真正容易被忽略的点是:你写的“单线程高频同步”,在 JIT 眼里可能根本不是单线程上下文 —— 只要存在任何逃逸线索(比如传给 System.out.println() 或 Arrays.asList()),锁消除就会失效,此时禁用偏向锁反而让轻量级锁成为唯一选项,而它的固定开销就浮出水面了。










