monitorenter和monitorexit字节码是否真的不像下面的代码一样堆叠?
monitorenter;
//code1
monitorenter;
//code2
monitorexit;
//code3
monitorexit;
代码3不会执行吗?怎么补救?
修改 “不要堆叠”我的意思是:如果在显示器内部输入显示器,是否会造成一些麻烦?
答案 0 :(得分:1)
解释后......
我知道只有一个可能的问题当"监视器已进入监视器时#34;。当第一个线程做这样的事情时,这就是一个僵局:
synchronized (object1) { // monitorenter for object1
// code1
synchronized (object2) { // monitorenter for object2
//code2
}
//code3
}
和第二个:
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 :(得分:1)
您可能听说过Java语言中synchronized
的功能并未完全映射到monitorenter
/ monitorexit
Java字节码指令。确切的细节是:
monitorenter
和monitorexit
执行“嵌套”,即增加特定对象实例的锁定计数,只有当计数器再次达到零时才会释放。但是,与synchronized
语句不同,JVM不会强制执行monitorenter
和monitorexit
指令的配对。因此,保证在离开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 为监视器。然后:
方法调用期间 T 在 M 上执行的监视条目数必须等于 T 在方法调用期间 M ,无论方法调用是正常还是突然完成。
- 醇>
在方法调用期间,由于方法调用超过了执行的监视条目数,因此 T 在 M 上执行的监视器退出次数可能不会超过自方法调用以来 M 上的 T 。