在讨论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
')监视器.
我不知道不同的字节码,我会很高兴听到差异.但在实践中,它们是完全相同的.
编辑:我将澄清这一点,因为有些人在这里弄错了.考虑:
public class A { public synchronized void doStuff() { // do stuff } } public class B extends A { public void doStuff() { // do stuff // THIS IS OVERRIDE! } }
在这种情况下doStuff()
,doStuff()
即使不同步,B类仍会覆盖A类.
同步关键字永远不是合同的一部分!不适用于子类,不适用于接口,不适用于抽象类.