synchronized 锁消除是什么
锁消除是 java hotspot 虚拟机在即时编译(jit)阶段采用的一种同步省略技术,其核心目的是移除那些本不该存在的重量级锁以提升性能。当 jit 编译器通过逃逸分析发现某个对象仅在当前线程或方法内使用,且不会逃逸到外部时,就会判定该处的 synchronized 块是不必要的,从而直接将其消除。这样做不仅避免了加锁和解锁带来的系统开销,还让代码执行效率接近于无同步操作的状态。

如何触发锁消除机制
要触发锁消除,开发者需要编写一段包含局部变量同步的代码,并确保这些变量没有发生逃逸。在默认情况下,HotSpot 虚拟机通常会自动开启逃逸分析和锁消除功能,因此你不需要手动配置参数,只需关注代码逻辑即可。只要对象的生命周期被严格限制在方法栈帧内部,JVM 就能识别出这种“不安全的”但实际安全的同步行为并予以优化。

public class LockEliminationDemo {
public static void main(String[] args) {
long start = System.currentTimeMillis();
// 循环执行以激发 JIT 编译
for (int i = 0; i <p>运行上述代码时,虽然我们在 <code>concatString</code> 方法中对局部变量 <code>sb</code> 使用了 <code>synchronized</code>,但由于 <code>sb</code> 是局部变量且未返回或泄露给其他线程,JIT 编译器会将其识别为可消除的锁。最终生成的机器码中不包含任何锁指令,从而实现了极高的执行速度。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill12680" title="JavaScript 开发专家"><img
src="https://img.php.cn/upload/skill/001/246/273/6adaf20dee630206.jpg" alt="JavaScript 开发专家" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill12680" title="JavaScript 开发专家" class="overflowclass">JavaScript 开发专家</a>
<p class="overflowclass">掌握包含 ES6+、异步模式和 Node.js API 的现代 JavaScript。处理 Promise、事件循环和浏览器/Node 兼容性。在 JavaSc</p>
</div>
<a rel="nofollow" href="/xiazai/skill12680" title="JavaScript 开发专家" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><h2>锁消除对 StringBuilder 的影响</h2><p>在 Java 开发中,最典型的锁消除应用场景就是 <code>StringBuilder</code> 的使用。由于 <code>StringBuilder</code> 本身是非线程安全的,但在单线程环境下进行字符串拼接时,我们往往习惯性地对其加锁以保证安全,或者在某些旧版本代码中为了兼容而保留锁。锁消除机制能够精准地识别出这种“过度保护”,并将其彻底移除。</p><p><img src="https://img.php.cn/upload/article/001/242/473/179453811118784.png?x-oss-process=image/resize,p_40" alt="Java synchronized 中 锁消除是什么"></p><pre class="brush:php;toolbar:false;">// 对比:如果 sb 逃逸了,锁就不会被消除
public class EscapingObject {
private static StringBuilder sharedSb = new StringBuilder();
public static void unsafeAppend() {
StringBuilder sb = new StringBuilder();
synchronized (sb) { // 注意:这里锁的是局部变量 sb,不是 sharedSb
sb.append("test");
}
sharedSb.append(sb); // sb 的内容被共享,但 sb 对象本身仍可能被优化
}
}
在上述代码中,即使我们将 sb 的内容追加到了静态变量 sharedSb 中,只要 sb 对象本身没有作为引用返回或被其他线程直接访问,JIT 依然可能对其内部的同步块进行优化。然而,如果我们将 sb 直接赋值给静态变量或返回它,即发生了逃逸,那么 synchronized 锁将不会被消除,因为此时该对象确实需要在线程间保持可见性和原子性。理解这一点有助于开发者在编写高性能代码时,合理设计对象的作用域,避免不必要的同步开销。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










