用于Java中的实例方法同步的等效代码

elj*_*nso 8 java synchronization

在讨论Java同步问题时,有人评论说下面的代码片段不相同(并且可能编译为不同的字节码):

public synchronized void someMethod() {
  //stuff
}
Run Code Online (Sandbox Code Playgroud)

public void someMethod() {
  synchronized (this) {
    //stuff
  }
}
Run Code Online (Sandbox Code Playgroud)

它们是等价的吗?

Dav*_* L. 13

虽然我测试的编译器(Java 1.6.0_07和Eclipse 3.4)生成不同的字节码,但它们在功能上是等价的.第一个产生:

// access flags 33
public synchronized someMethod()V
  RETURN
Run Code Online (Sandbox Code Playgroud)

第二个产生:

// access flags 1
public someMethod()V
  ALOAD 0
  DUP
  MONITORENTER
  MONITOREXIT
  RETURN
Run Code Online (Sandbox Code Playgroud)

(感谢ASM进行字节码打印).

因此它们之间的区别仍然存在于字节码级别,并且由JVM决定它们的行为是否相同.但是,它们确实具有相同的功能效果 - 请参阅Java语言规范中的示例.

应该注意的是,如果在子类中重写该方法,则它不一定是同步的 - 因此在这方面也没有区别.

我还运行了一个测试来阻止一个线程试图在每种情况下访问监视器,以比较它们的堆栈跟踪在线程转储中的样子,并且它们都包含有问题的方法,因此也没有区别.


Yuv*_*dam 7

我做了原始评论,声明是相同的.

在这两种情况下,首先发生的事情是调用线程将尝试获取当前对象(意思是this')监视器.

我不知道不同的字节码,我会很高兴听到差异.但在实践中,它们是完全相同的.

编辑:我将澄清这一点,因为有些人在这里弄错了.考虑:

public class A {
    public synchronized void doStuff()
    {
        // do stuff
    }
}

public class B extends A {
    public void doStuff()
    {
        // do stuff
        // THIS IS OVERRIDE!
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下doStuff(),doStuff()即使不同步,B类仍会覆盖A类.

同步关键字永远不是合同的一部分!不适用于子类,不适用于接口,不适用于抽象类.