解读synchronized锁的释放机制

 更新时间:2025年04月17日 16:44:15   作者:堕落年代  
这篇文章主要介绍了synchronized锁的释放机制,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

synchronized锁的释放机制

synchronized 锁的释放机制是通过 JVM 底层的 Monitor 锁模型计数器机制 实现的。

以下是具体的释放逻辑和触发条件:

一、锁释放的触发条件

正常执行结束

当线程执行完 synchronized 修饰的代码块或方法时,JVM 会自动调用 monitorexit 指令释放锁。

  • 同步代码块:通过 monitorentermonitorexit 指令显式控制锁的获取与释放。
  • 同步方法:通过 ACC_SYNCHRONIZED 标志隐式触发锁的获取和释放,方法结束时自动释放锁。

异常退出

  • 如果在 synchronized 代码块或方法中抛出未捕获的异常,JVM 会执行 monitorexit 指令释放锁。
  • 编译时会为同步代码块生成两个 monitorexit 指令:一个用于正常退出,另一个用于异常路径。

显式调用 wait()

  • 线程在 synchronized 代码块内调用 wait() 方法时
  • 会暂时释放锁并进入等待状态,直到其他线程调用 notify()/notifyAll() 唤醒它

二、锁释放的核心机制

计数器递减

  • 每个对象关联一个 Monitor 锁,内部维护一个计数器(_count)。
  • 线程每次进入 synchronized 代码块时计数器加 1,退出时减 1。
  • 当计数器归零时,锁完全释放,其他线程可竞争获取。

Monitor 对象的状态管理

  • 持有锁的线程(_owner:释放锁后,_owner 置为 null,计数器归零。
  • 等待队列(_EntryList_WaitSet:锁释放后,JVM 会从 _EntryList_WaitSet 中唤醒线程重新竞争锁。

三、不同场景的锁释放示例

1. 同步代码块

public void method() {
    synchronized (this) {
        // 代码逻辑
    } // 此处自动执行 monitorexit 释放锁
}

无论正常结束还是抛出异常,monitorexit 都会触发锁释放。

2. 同步方法

public synchronized void method() {
    // 代码逻辑
} // 方法结束自动释放锁

通过 ACC_SYNCHRONIZED 标志隐式管理锁,无需显式字节码指令。

3. 异常场景

public void method() {
    synchronized (this) {
        throw new RuntimeException(); // 触发异常,自动释放锁
    }
}

即使未捕获异常,JVM 也会执行 monitorexit 指令释放锁。

四、锁释放的底层实现(字节码层面)

同步代码块

编译后生成 monitorenter 和两个 monitorexit(正常退出和异常退出)指令:

public void method();
  Code:
     0: aload_0
     1: dup
     2: astore_1
     3: monitorenter     // 获取锁
     4: ...              // 业务代码
    13: monitorexit      // 正常退出释放锁
    14: goto 20
    17: aload_1
    18: monitorexit      // 异常退出释放锁
    19: athrow
    20: return

同步方法

方法访问标志包含 ACC_SYNCHRONIZED,JVM 在方法入口和出口隐式管理锁。

五、注意事项

不会释放锁的操作

  • Thread.sleep()Thread.yield() 不会释放锁。
  •  线程挂起(如 suspend())也不会释放锁。

可重入性

  • 同一线程可多次获取锁(计数器递增)
  • 需对应次数的退出操作才能完全释放

总结

synchronized 锁的释放依赖于 JVM 的 Monitor 模型和计数器机制,通过以下方式触发:

  1. 代码块或方法正常结束。
  2. 未捕获异常抛出。
  3. 显式调用 wait()
  4. 其底层通过 monitorexit 指令或隐式标志确保锁的正确释放,保障线程安全。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java 中Flyway的使用详解

    Java 中Flyway的使用详解

    这篇文章主要介绍了Java 中Flyway的使用详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07
  • 设置JavaScript自动提示-Eclipse/MyEclipse

    设置JavaScript自动提示-Eclipse/MyEclipse

    自动提示需要2个组件,分别是:ext-4.0.2a.jsb2||spket-1.6.16.jar,需要的朋友可以参考下
    2016-05-05
  • Springboot系列之kafka操作使用详解

    Springboot系列之kafka操作使用详解

    这篇文章主要为大家介绍了Springboot系列之kafka操作使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • Java十分钟精通异常处理机制

    Java十分钟精通异常处理机制

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等
    2022-03-03
  • Java 中的vector和list的区别和使用实例详解

    Java 中的vector和list的区别和使用实例详解

    在大家还没有了解vector,list,deque的知识之前,我先给大家介绍下stl,本文重点给大家介绍vector和list的区别及使用,感兴趣的的朋友一起看看吧
    2017-09-09
  • 深入了解JAVA HASHMAP的死循环

    深入了解JAVA HASHMAP的死循环

    HASHMAP基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。(除了非同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同。)下面小编来带大家详细了解下吧
    2019-06-06
  • 如何查看java进程内存占用情况

    如何查看java进程内存占用情况

    这篇文章主要介绍了如何查看java进程内存占用情况问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • 详解RocketMQ 消费端如何监听消息

    详解RocketMQ 消费端如何监听消息

    这篇文章主要为大家介绍了RocketMQ 消费端如何监听消息示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • java+testng+selenium的自动化测试实例

    java+testng+selenium的自动化测试实例

    这篇文章主要介绍了java+testng+selenium的自动化测试实例,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • Java8函数式接口的基础学习教程

    Java8函数式接口的基础学习教程

    这篇文章主要给大家介绍了关于Java8函数式接口基础学习的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04

最新评论