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其中一个才能进入
相关推荐
魔道不误砍柴功1 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_2341 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
Nu11PointerException1 小时前
JAVA笔记 | ResponseBodyEmitter等异步流式接口快速学习
笔记·学习
闲晨1 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
测开小菜鸟3 小时前
使用python向钉钉群聊发送消息
java·python·钉钉
P.H. Infinity4 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天4 小时前
java的threadlocal为何内存泄漏
java
caridle4 小时前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
^velpro^4 小时前
数据库连接池的创建
java·开发语言·数据库
苹果醋34 小时前
Java8->Java19的初步探索
java·运维·spring boot·mysql·nginx