Java中实例方法同步的等效代码
在讨论Java同步问题时,有人发表评论说以下片段不等同(可能编译为不同的字节码):
public synchronized void someMethod() {
//stuff
}
和
public void someMethod() {
synchronized (this) {
//stuff
}
}
它们是否相同?
它们在功能上是等价的,尽管我测试的编译器(Java 1.6.0_07和Eclipse 3.4)生成不同的字节码。 第一个生成:
// access flags 33
public synchronized someMethod()V
RETURN
第二个生成:
// access flags 1
public someMethod()V
ALOAD 0
DUP
MONITORENTER
MONITOREXIT
RETURN
(感谢ASM的字节码打印)。
所以它们之间的差异会持续到字节码级别,并且由JVM决定其行为是否相同。 但是,它们具有相同的功能效果 - 请参阅Java语言规范中的示例。
应该指出的是,如果方法在子类中被覆盖,它不一定是同步的 - 所以在这方面也没有区别。
我还运行了一个测试,以阻止一个线程在每种情况下尝试访问监视器,以比较它们的堆栈跟踪在线程转储中的样子,并且它们都包含有问题的方法,因此在那里也没有区别。
我原来的评论是这些陈述是相同的。
在这两种情况下,首先发生的事情是调用线程将尝试获取当前对象的(意思是this
)监视器。
我不知道不同的字节码,我很乐意听到它们的差异。 但实际上,它们是100%相同的。
编辑:我要澄清这一点,因为这里有些人错了。 考虑:
public class A {
public synchronized void doStuff()
{
// do stuff
}
}
public class B extends A {
public void doStuff()
{
// do stuff
// THIS IS OVERRIDE!
}
}
在这种情况下doStuff()
在B类还是重写doStuff()
在A类,即使它是不同步的。
同步关键字不属于合同的一部分! 不适用于子类,不适用于接口,不适用于抽象类。
我做了原始评论。 我的评论是他们在逻辑上是等价的,但是编译成不同的字节码 。
我当时没有添加任何其他证明,因为没有什么需要证明的 - 他们只是编译成不同的字节码。 如果将方法声明为synchronized,则该同步是方法定义的一部分。 方法中的同步块不是方法定义的一部分 ,而是涉及单独的字节码来获取和释放显示器,如上面海报中的一个所示。 严格地说,它们有些不同,但是对于程序的整体逻辑来说,它们是相同的 。
这是否重要? 那么,在大多数现代桌面虚拟机上,几乎没有。 但是例如:
上一篇: Equivalent code for instance method synchronization in Java
下一篇: When to throw IllegalStateException vs IllegalArgumentException?