Java monitorexit指令有2次
1.结论:
保证线程出现异常,锁也可以被释放
编写一个测试方法:
public void f(){
synchronized (this){
int x = 1;
}
}
查看该方法生成的字节码:
0 aload_0 //从局部变量表下标为0的位置,加载锁对象到栈
1 dup //在栈顶复制该对象
2 astore_1 //将栈顶对象(锁对象)保存到局部变量表1的位置。
3 monitorenter //获取锁
4 iconst_1 //4,5完成x=1
5 istore_2
6 aload_1 //将锁对象取到栈顶
7 monitorexit //释放锁
8 goto 16 (+8) //跳到return语句,代码执行结束返回。
11 astore_3 //执行语句11表示,上述代码出现异常,将异常对象保存到局部变量表位置为3处。
12 aload_1 //同6
13 monitorexit //同7
14 aload_3 //加载异常对象到栈顶
15 athrow //抛出异常
16 return //代码执行结束,返回
可以看出:3行是一个monitorenter,但是7,13行各有一个monitorexit。
想要了解上述字节码运行,首先的知道异常表。
2.异常表
异常表的每一条记录结构如下:它包含4个字段,这些字段的含义为:如果当字节码在第start_pc
行到第end_pc
行之间(不包含end_pc
行)出现了类型为catch_type
或者其子类的异常(catch_type
为指向一个CONSTANT_Class_info
型常量的索引),则转到第handler_pc
行继续处理。当catch_type
的值为0时,代表任意异常情况都需要转向到handler_pc
处进行处理。
exception_table {
u2 start_pc;
u2 end_pc;
u2 handler_pc;
u2 catch_type;
}
查看上述代码的异常表:
Nr. | start_pc | end_pc | handler_pc | catch_type |
---|---|---|---|---|
0 | 4 | 8 | 11 | 0(any) |
1 | 11 | 14 | 11 | 0(any) |
即:
从字节码第4到8行出现异常,则转到第11行运行,11行到15行中有monitorexit会释放锁。