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,则该同步是方法定义的一部分。 方法中的同步块不是方法定义的一部分 ,而是涉及单独的字节码来获取和释放显示器,如上面海报中的一个所示。 严格地说,它们有些不同,但是对于程序的整体逻辑来说,它们是相同的

这是否重要? 那么,在大多数现代桌面虚拟机上,几乎没有。 但是例如:

  • 原则上虚拟机可以在一种情况下进行优化,但不能在另一种情况下进行优化
  • 有一些JIT编译器优化,其中方法中的字节码数量被视为什么优化做出的标准
  • 没有JIT编译器的虚拟机(当然很少有,但可能在旧的移动设备上?)每个调用都会有更多的字节码处理
  • 链接地址: http://www.djcxy.com/p/76241.html

    上一篇: Equivalent code for instance method synchronization in Java

    下一篇: When to throw IllegalStateException vs IllegalArgumentException?