在Java中堆叠monitorenter和monitorexit

时间:2014-09-30 06:01:48

标签: java concurrency synchronization

monitorenter和monitorexit字节码是否真的不像下面的代码一样堆叠?

monitorenter;
//code1
    monitorenter;
    //code2
    monitorexit;
//code3
monitorexit;

代码3不会执行吗?怎么补救?

修改 “不要堆叠”我的意思是:如果在显示器内部输入显示器,是否会造成一些麻烦?

2 个答案:

答案 0 :(得分:1)

解释后......

  1. 我知道只有一个可能的问题当"监视器已进入监视器时#34;。当第一个线程做这样的事情时,这就是一个僵局:

    synchronized  (object1) { // monitorenter for object1
        // code1
        synchronized (object2) { // monitorenter for object2
            //code2
        }
        //code3
    }
    
  2. 和第二个:

        synchronized  (object2) { // monitorenter for object2
            // code2.1
            synchronized (object1) { // monitorenter for object1
               //code2.2
            }
           //code2.3
        }
    

    当code1在object1上执行锁定并且code2.1在object2上的锁定下执行时,我们遇到了死锁。第一个线程将在object1完成后等待object2,第二个线程将无限期地等待object1。这是一个堆栈"。嵌套锁定有一个通用规则:在所有线程中使用相同的锁定顺序。或者只是消除嵌套锁。

    如果你第二次为一个实例做monitorenter

        synchronized  (object1) { // monitorenter for object1
            // code1
            synchronized (object1) { // monitorenter for object1
                //code2
            }
            //code3
        }
    

    JDK 7 with -XX:+ EliminateNestedLocks(" on"默认情况下),当monitor对象是静态final或锁定此对象时,将代码优化为:

        synchronized  (object1) { // monitorenter for object1
            //code1
            //code2
            //code3
        }
    
    1. 无论如何,如果你看到code2被执行(当然没有例外),那么必须启动code3

答案 1 :(得分:1)

您可能听说过Java语言中synchronized的功能并未完全映射到monitorenter / monitorexit Java字节码指令。确切的细节是:

monitorentermonitorexit执行“嵌套”,即增加特定对象实例的锁定计数,只有当计数器再次达到零时才会释放。但是,与synchronized语句不同,JVM不会强制执行monitorentermonitorexit指令的配对。因此,保证在离开synchronized语句后,无论正常还是异常,锁将被释放(或内部计数器减少),必须由编译器通过发出相当于以下伪代码的代码来强制执行:

monitorenter(object);
try {
   // contents of the synchronized block
}
finally {
   monitorexit(object);
}

JVM将接受没有这种强保护的字节代码。该规范使JVM实现可以在方法退出时检查悬空monitorenter。我最后一次检查它时,Oracle的JVM做了这样的测试并重置了方法出口的锁定状态。如果使用不成对的监视操作进行常规方法退出,则会生成IllegalMonitorStateException

引用relevant part of the specification

  

结构化锁定是在方法调用期间,给定监视器上的每个出口与该监视器上的前一个条目匹配的情况。由于无法保证提交给Java虚拟机的所有代码都将执行结构化锁定,因此允许实施Java虚拟机,但不需要强制执行以下两个保证结构化锁定的规则。设 T 为线程, M 为监视器。然后:

     
      
  1. 方法调用期间 T M 上执行的监视条目数必须等于 T 在方法调用期间 M ,无论方法调用是正常还是突然完成。

  2.   
  3. 在方法调用期间,由于方法调用超过了执行的监视条目数,因此 T M 上执行的监视器退出次数可能不会超过自方法调用以来 M 上的 T

  4.