您的位置:首页 > 其它

jvm monitorenter monitor 指令

2016-03-10 16:05 471 查看
jvm虚拟指令集

假定:“必须”的含义

对于jvm指令的一些“必须”的要求,在运行期要求javaclass的结构是满足约束的,对于不满足约束的情况,jvm的行为是未定义的。

保留操作码

在java class文件中使用的指令操作码,有三个操作码是保留的,供java虚拟机内部使用。

254(0xfe)和255(0xff),分别有助记符impdep1和impdep2,目的是在软件或者硬件实现的特定功能提供“后门”或陷阱。

202(0xca),有助记符breakpoint,目的是由调试程序使用来实现断点。

虚拟机错误

当内部错误或者资源限制导致java语言语义不能实现时,jvm抛出一个VirtualMachineError类的子类的实例。jvm规范不规定和语言抛出的时间和地点。

jvm指令集

我不一一例举各种指令的操作码和用法,需要时去查就行了。

第七章 为jvm编译

java编译成为class文件之后,以类汇编的jvm操作指令方式存在,jdk自带的javap程序具有这样的功能,将class文件翻译为这样的指令集。

下面是我测试的一个实例:

源文件为test.java

public class test {

    public static String a = "";

    public int i =0;

    public test() {

        int i=0;

        String a = "xyz";

    }

}

编译完成为test.class,用javap生成之后输出结果为:

javap -c  -classpath "c:/" test

public class test extends java.lang.Object{

public static java.lang.String a;

public int i;

static {};

  Code:

   0:   ldc     #4; //String

   2:   putstatic       #5; //Field a:Ljava/lang/String;

   5:   nop

   6:   return

public test();

  Code:

   0:   aload_0

   1:   invokespecial   #1; //Method java/lang/Object."":()V

   4:   aload_0

   5:   iconst_0

   6:   putfield        #2; //Field i:I

   9:   iconst_0

   10:  istore_1

   11:  ldc     #3; //String xyz

   13:  astore_2

   14:  nop

   15:  return

}

7.2常数、局部变量和控制结构的使用

jvm是面向栈的,大多数操作都是从当前框架的操作数栈中取得操作数。

7。3运算

jvm一般在操作数栈上进行运算,即从栈中取操作数,并将结果存入操作数栈中。

7。4访问常数池

byte,char,short,以及小int值都可以通过立即数的方式编译在method的code中,但是int,long,float,double,以及string实例的引用,就需要对常数池进行访问了。使用ldc,ldc_w,ldc2_w指令管理。

7.5更多控制范例

可供查阅

7。6接收参数

如果向java实例方法传递了n个参数,它们被接收,按约定,框架的编号1到n的局部变量为新的方法调用创建,顺序为接收的顺序。

7。7调用方法

对java实例方法的调用,是在对象的运行期类型上调度的。用invokevirtual实现,将其参数取做对常数池表项的索引,给出对象的类类型的完整限定符名称,再调用方法的名称和方法的描述符。

对java静态(类)方法的调用,无需传递类实例,其余和实例方法相似,用invokespecial方法实现。

invokespecail指令用于调用实例初始化方法。超类方法和调用private方法。

7。8处理类实例

构建一个类实例的过程,在建立对象及其实例域之后,用invokespecial调用相应构造函数对应的方法来初始化对象。

对对象域的访问用getfield和putfield指令完成。

7。9数组

主要讲的是数组操作的相关jvm指令,如:newarray,过一遍,可以查阅。

7。10编译开关

对于java的switch指令,jvm有对应的两种指令:tableswitch,lookupswitch.

tableswitch指定取值范围,而lookupswitch并不指定取值范围,两者如何选择完全由效率选择决定。

7。11对操作数栈的操作

jvm有大量的指令补充,将操作数栈的内容作为无类型字或成对的无类型字操纵。便于jvm虚拟机指令的灵活组成。

如dup,dup_x2等,都是对字或者双字进行操作。

7。12抛出或者处理异常

jvm中try...catch块的处理对于jvm指令处理是透明的,辅助控制是由异常表来完成的,由异常表来决定到哪里去调用处理,哪些部分的异常是受控的。

7。13编译finally

try.....finally语句与try-catch相似,只是其辅助控制是由指令jsr(子例程调用)显式的表示,在jsr调用之前,将下一指令的地址压入栈中。而异常表只控制try块的范围。

7。14同步

jvm用monitorenter和monitorexit指令对同步提供显式支持。而java常用sychronized方法。

sychronized“方法”通常不是用monitorenter和monitorexit指令实现的。往往是由“方法调用指令”检查常数池里的ACC_SYCHRONIZED标志

但monitorenter和monitorexit指令是为了支持sychronized“语句”而存在的。

注意这里的方法和语句的区别。

语句实例如下:test.java

public class test {

  public test() {

  }

  public static void main(String[] args) {

    synchronized(new Object()){

        int i = 0;

    }

  }

}

编译完的结果:

C:\JBuilderX\bin>javap -c  -classpath "d:/epm40/classes" test

public class test extends java.lang.Object{

public test();

  Code:

   0:   aload_0

   1:   invokespecial   #1; //Method java/lang/Object."":()V

   4:   nop

   5:   return

public static void main(java.lang.String[]);

  Code:

   0:   new     #2; //class Object

   3:   dup

   4:   invokespecial   #1; //Method java/lang/Object."":()V

   7:   dup

   8:   astore_1

   9:   monitorenter // Enter the monitor associated with object

   10:  iconst_0

   11:  istore_2

   12:  nop

   13:  aload_1

   14:  monitorexit // Exit the monitor associated with object

   15:  goto    23

   18:  astore_3

   19:  aload_1

   20:  monitorexit // Be sure to exit monitor...

   21:  aload_3

   22:  athrow

   23:  nop

   24:  return

  Exception table:

   from   to  target type

    10    15    18   any

    18    21    18   any

}

 

monitorenter和monitorexit

详见http://java.sun.com/docs/books/vmspec/2nd-edition/html/Instructions2.doc9.html

The objectref must be of type reference.

Each object has a monitor associated with it. The thread that executes
monitorenter gains ownership of the monitor associated with objectref.
If another thread already owns the monitor associated with objectref,
the current thread waits until the object is unlocked, then tries again
to gain ownership. If the current thread already owns the monitor
associated with objectref, it increments a counter in the monitor
indicating the number of times this thread has entered the monitor. If
the monitor associated with objectref is not owned by any thread, the
current thread becomes the owner of the monitor, setting the entry count
of this monitor to 1.

monitorenter操作的目标一定要是一个对象,类型是reference。Reference实际就是堆里的一个存放对象的地
址。每个对象(reference)都有一个monitor对应,如果有其它的线程获取了这个对象的monitor,当前的线程就要一直等待,直到获得
monitor的线程放弃monitor,当前的线程才有机会获得monitor。

如果monitor没有被任何线程获取,那么当前线程获取这个monitor,把monitor的entry count设置为1。表示这个monitor被1个线程占用了。

当前线程获取了monitor之后,会增加这个monitor的时间计数,来记录当前线程占用了monitor多长时间。

 

源博客--http://www.blogjava.net/flyffa/archive/2006/08/24/65566.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: