当前位置: 首页 > article >正文

monitorenter /moniterexit

在 Java 中,同步代码块通过 monitorentermoniterexit 字节码指令来保证同一时刻只有一个线程能够进入同步代码块,下面从监视器(Monitor)的概念、monitorentermoniterexit 的工作流程以及锁的状态几个方面详细阐述其实现原理。

监视器(Monitor)的概念

每个 Java 对象都可以关联一个监视器(Monitor),监视器是 Java 中实现同步的基础,它本质上是一个同步工具,也可以理解为一种锁的实现。监视器有一个重要的属性:进入数(Entry Count),用于记录有多少个线程进入了该监视器。当进入数为 0 时,表示该监视器没有被任何线程持有;当有线程进入监视器时,进入数会加 1;当线程退出监视器时,进入数会减 1。

monitorenter 指令的工作流程

当 JVM 执行到 monitorenter 指令时,会按照以下步骤尝试获取对象关联的监视器:

  1. 检查监视器的进入数:首先检查对象关联的监视器的进入数是否为 0。
    • 如果进入数为 0,说明该监视器没有被任何线程持有,当前线程可以成功获取该监视器,将进入数设置为 1,同时该线程成为监视器的所有者,然后继续执行同步代码块中的代码。
    • 如果进入数不为 0,说明已经有其他线程持有了该监视器,此时当前线程会被阻塞,进入等待队列,直到监视器的进入数变为 0 时,再尝试获取监视器。
  2. 可重入性:如果当前线程已经是该监视器的所有者,再次执行 monitorenter 指令时,监视器的进入数会加 1,而不是被阻塞。这就是 Java 中 synchronized 的可重入特性,允许同一个线程多次进入同一个同步代码块,避免了死锁的发生。

moniterexit 指令的工作流程

当 JVM 执行到 moniterexit 指令时,会按照以下步骤释放对象关联的监视器:

  1. 减少进入数:将监视器的进入数减 1。
  2. 判断是否释放监视器:如果进入数减为 0,说明当前线程已经完全退出了该同步代码块,会释放该监视器,唤醒等待队列中等待获取该监视器的线程,让它们有机会竞争获取监视器。
  3. 异常处理:在同步代码块中,如果发生异常,也会执行 moniterexit 指令,确保监视器能够被正确释放,避免出现死锁的情况。这就是为什么在字节码中会有两个 moniterexit 指令,一个用于正常退出同步代码块,另一个用于异常退出同步代码块。

示例代码及字节码分析

public class SynchronizedBlockExample {
    public void test() {
        Object lock = new Object();
        synchronized (lock) {
            // 同步代码
        }
    }
}

对应的字节码片段:

  public void test();
    Code:
       0: new           #2                  // class java/lang/Object
       3: dup
       4: invokespecial #1                  // Method java/lang/Object."<init>":()V
       7: astore_1
       8: aload_1
       9: monitorenter  // 进入同步块,尝试获取监视器
      10: aload_1
      11: monitorexit   // 正常退出同步块,释放监视器
      12: goto          20
      15: astore_2
      16: aload_1
      17: monitorexit   // 异常退出同步块,释放监视器
      18: aload_2
      19: athrow
      20: return

通过 monitorentermoniterexit 指令以及监视器的进入数机制,Java 保证了同一时刻只有一个线程能够进入同步代码块,从而实现了线程同步。


http://www.kler.cn/a/538930.html

相关文章:

  • 爬虫技巧汇总
  • c++:list
  • Jupyter Notebook自动保存失败等问题的解决
  • 跟我学C++高级篇——CRTP的高级应用
  • Linux网卡配置方法
  • 多线程操作
  • Oracle数据连接 Dblink
  • 四次挥手详解
  • PID 算法简介(C语言)
  • Ai无限免费生成高质量ppt教程(deepseek+kimi)
  • 【数论】—— 欧拉函数
  • Linux下安装SVN服务端小白教程
  • 解锁Rust:融合多语言特性的编程利器
  • VLLM历次会议(2024.1)
  • 归一化与伪彩:LabVIEW图像处理的区别
  • ASAP Utilities:Excel 插件中的高效助手
  • (done) openMP学习 (Day10: Tasks 原语)
  • 【基于SprintBoot+Mybatis+Mysql】电脑商城项目之上传头像和新增收货地址
  • Elasticsearch入门技术:从零开始掌握全文搜索引擎
  • 深度理解如何使用DeepSeek-R1撰写论文:初学者指南
  • 校园网规划方案
  • 基于DeepSeek的具身智能高校实训解决方案——从DeepSeek+机器人到通用具身智能
  • DeepSeek JanusPro-7B本地安装-唯一正确版
  • 旋转位置编码(RoPE)公式详细推导过程
  • RocketMQ实战—8.营销系统业务和方案介绍
  • qt widget和qml界面集成到一起