java字节码分析(jclasslib)-synchronized原理

说明

原理:synchronized代码块同步,即一段指令系列的同步,主要是通过monitorenter、monitorexit来实现的,为了确保执行monitorenter后必须执行monitorexit,编译器会自动产生一个异常处理器,目的就是用来执行monitorexit;

下面将对下面代码进行字节码分析

package com.ydfind.test;

public class Monitor {
    private void test() {
        synchronized (this) {
            int a = 1;
        }
    }
    synchronized
    public void test1() {
    }
}

synchronized代码块分析

字节码

字节码及注释如下:
在这里插入图片描述

 0 aload_0       // 将this压入操作数栈
 1 dup           // 将栈顶this复制并压入栈
 2 astore_1      // 将栈顶this放入变量1。变量1是准备做为monitorexit的参数
 3 monitorenter  // 尝试持有栈顶this的管程(this出栈后,栈就空了)
 // 下面2行实现int a = 1功能,1保存在变量2里面
 4 iconst_1
 5 istore_2
 6 aload_1       // monitorexit this
 7 monitorexit
 8 goto 16 (+8)
 11 astore_3     // 发生异常,将异常对象放入变量3----为什么不放入变量2呢?
 12 aload_1      // monitorexit this
 13 monitorexit
 14 aload_3      // monitorexit后再抛出异常
 15 athrow
 16 return

杂项

上面字节码astore_n中n最大为3,及局部变量表深度4;操作数栈开始时两个this,最大深度为2。与杂项里面的记录一致:
在这里插入图片描述

异常表

起始PC:异常处理器 监控代码的起始位置
结束PC:异常处理器 监控代码的结束位置(并不包括结束行,即[startPC,endPC))
跳转PC:处理异常的起始位置,比如catch代码块
捕获类型:异常处理器所捕获的异常类型

关于异常表如下所示。若是同步代码块出现异常,会跳到11行,正常情况下,释放管程后,再抛出异常;但若11-13行发生异常,会不断跳到11行,即不断尝试释放管程,这是确保异常发生时能确保管程能释放的保护机制。
在这里插入图片描述

行号表

起始PC: 字节码的起始位置;
行号:代码行号;
在这里插入图片描述

操作数栈

起始位置:变量作用域的起始位置
长度:变量作用域的长度。例子中this在0-16总共17行中生效,即函数内都有效;
序号:数组的下标
名字:变量的描述(变量类型+引用类型 or 基本类型)
在这里插入图片描述

synchronized方法分析

在这里插入图片描述
方法级的同步是隐式的,在方法的调用和返回操作之中实现。方法调用时,调用指令会检查方法的ACC_SYNCHRONIZED标志是否被设置了,若是被设置了,则当前线程需要持有管程才能执行方法,执行完成则会释放管程。在方法执行过程中,执行线程持有管程,故其它线程会无法获得管程而无法执行程序(竞争失败的线程会被放入entrylist);若是发生异常,且函数内部无法处理,那么管程会在 异常向外方法抛出时 自动释放。

上面可以看出,方法的访问标识里面有synchronized,则表示是同步方法。

运行时,jvm可以通过检查方法常量池的方法表结构的ACC_SYNCHRONIZED访问标志 得知该方法 是否被声明为同步方法。既然是方法常量池,则是在方法区。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值