欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

解读synchronized锁的释放机制,

来源: javaer 分享于  点击 42134 次 点评:71

解读synchronized锁的释放机制,


目录
  • 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 指令或隐式标志确保锁的正确释放,保障线程安全。

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持3672js教程。

    您可能感兴趣的文章:
    • Java中的synchronized锁膨胀详解
    • Java中Synchronized锁的使用和原理详解
    • Java中synchronized锁的深入理解
    • 浅谈Java的Synchronized锁原理和优化
    • 深入详解Java中synchronized锁升级的套路

    相关文章

      暂无相关文章
    相关栏目:

    用户点评