JVM学习-字节码指令集(四)

异常处理指令
抛出异常指令
  • athrow指令:在Java程序中显示抛出异常的操作(throw语句)都是由athrow指令来实现
  • 除了throw语句显示抛出异常情况之外,JVM规范还规定了许多运行时异常会在其他Java虚拟机指令检测到异常状况时自动抛出,在之前介绍的整数运算时,当除数为零时,虚拟机会在idiv或ldiv指令中抛出ArithmeticException异常
  • 注:正常情况下,操作数栈的压入弹出是一条条指令完成,唯一的例外情况是在抛异常时,Java虚拟机会清除操作数栈上的所有内容,而后将异常实例压入调用者操作数栈上
异常处理与异常表
处理异常
  • Java虚拟机中,处理异常 (catch语句)不是由字节码指令来实现,而是采用异常表来完成的
异常表
  • 如果一个方法定义了一个try-catch或者try-finally的异常处理,就会创建一个异常表,它包含了每个异常处理或者finally块的信息,异常表保存了每个异常处理信息,如
  • 起始位置
  • 结束位置
  • 程序计数器记录的代码处理的偏移地址
  • 被捕获的异常类在常量池中的索引
  • 当一个异常被抛出时,JVM会在当前的方法寻找一个匹配的处理,如果没有找到,这个方法会强制结束并弹出当前栈顶,并且异常会重新抛给上层调用的方法。如果在所有栈帧弹出前仍然没有找到合适的异常处理,这个线程将终止,如果这个异常在最后一个非守护线程里抛出,将会导致JVM自己终止,比如这个线程是个main线程
  • 不管什么时候抛出异常,如果异常处理最终匹配了所有异常类型,代码就会继续执行,这种情况下,如果方法结束后没有抛出异常,仍然执行finally块,在return前,它直接跳到finally块来完成目标
同步控制指令--通过monitor支持
方法级同步
  • 方法级同步是隐式的,即无须通过字节码指令来控制,它实现在方法调用和返回操作中,虚拟机可以从方法常量池的方法表结构中的ACC_SYCHRONIZED访问标志得知一个方法是否声明为同步方法
  • 当调用方法时,调用指令将会检查方法的ACC_SYCHRONIZED访问标志是否设置
  • 如果设置了,执行线程将先持有同步锁,然后执行方法,最后在方法完成时释放同步锁
  • 在方法执行期间,执行线程有了同步锁,其他任何线程都无法再获得一个锁
  • 如果一个同步方法执行期间抛出了异常,并且在方法内部无法处理此异常,那这个同步方法所持有的锁都将在异常抛到同步方法外自动释放
java 复制代码
private int i = 0;
    public synchronized void add() {
        i++;
    }
//字节码
 0 aload_0
 1 dup
 2 getfield #2 <com/chapter10/SychronizedTest.i>
 5 iconst_1
 6 iadd
 7 putfield #2 <com/chapter10/SychronizedTest.i>
10 return
  • 注:这段代码和普通无同步操作代码没有不同,没有使用monitorenter和monitorexit进行同步区控制,因为对于同步方法而言,当虚拟机通过方法的访问标示符判断是一个同步方法时,会自动在方法调用前进行加锁,不同步方法执行完毕后,不管方法是正常结束还是有异常抛出,均由虚拟机释放这个锁,因此,对于同步方法而言,monitorenter和monitorexit指令是隐式存在的,并未直接出现在字节码中。
方法内部一段指令序列的同步
  • 同步一段指令集序列:通常是由java中的sychronized语句块来表示的,JVM的指令集有monitorenter和monitorexit两条指令来支持sychronized关键字的语义。
  • 当一个线程进入同步代码块时,它使用monitorenter指令请求进入,如果当前对象的监视器计数器为0,则它会被准许进入,若为1,则判断持有当前监视器的线程是否为自己,如果是,则进入,否则进行等待,直到对象的监视器计数器为0,才会被允许进入同步块
  • 当线程退出同步块时,需要使用monitorexit声明退出,在Java虚拟机中,任何对象都有一个监视器与之相关联,用来判断对象是否被锁定,当监视器被持有后,对象处于锁定状态
  • 指令monitorenter和monitorexit在执行时,需要在操作数栈顶压入对象,之后monitorenter和monitorexit的锁定和释放都是针对这个对象的监视器进行的
  • 监视器如何保护临界区代码不同时被多个线程访问,只有当线程4离开临界区时,线程1-3其中一个才能进入
相关推荐
scott.cgi2 小时前
Unity直接编译Java文件作为插件,导致失败的两个打包设置
java·unity·unity调用java·unity的java文件·unity的android插件·unity调用android·unity加载java代码
澈2076 小时前
C++并查集:高效解决连通性问题
java·c++·算法
2401_873479407 小时前
运营活动被薅羊毛怎么防?用IP查询+设备指纹联动封堵漏洞
java·网络·tcp/ip·github
ShiJiuD6668889997 小时前
大事件板块一
java
摇滚侠7 小时前
@Autowired 和 @Resource 的区别
java·开发语言
2301_783848658 小时前
优化文本分类中堆叠模型的网格搜索性能:避免训练卡顿的实战指南
jvm·数据库·python
SeaTunnel8 小时前
(八)收官篇 | 数据平台最后一公里:数据集成开发设计与上线治理实战
java·大数据·开发语言·白鲸开源
CLX05058 小时前
如何安装Oracle 12c Cloud Control_OMS服务端组件与Agent部署
jvm·数据库·python
吴声子夜歌9 小时前
Java——线程的基本协作机制
java·线程协作
谙弆悕博士9 小时前
【附C++源码】从零开始实现 2048 游戏
java·c++·游戏·源码·项目实战·2048