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

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

public synchronized void someMethod() { //stuff } 

 public void someMethod() { synchronized (this) { //stuff } } 

它们是等价的吗?

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

 // access flags 33 public synchronized someMethod()V RETURN 

第二个产生:

 // access flags 1 public someMethod()V ALOAD 0 DUP MONITORENTER MONITOREXIT RETURN 

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

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

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

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

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

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

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

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

 public class A { public synchronized void doStuff() { // do stuff } } public class B extends A { public void doStuff() { // do stuff // THIS IS OVERRIDE! } } 

在这种情况下,类B中的doStuff()仍会覆盖类A中的doStuff() ,即使它未同步。

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

我做了原始评论。 我的评论是它们在逻辑上是等价的,但是编译成不同的字节码

我当时没有添加任何其他东西来certificate它是正确的,因为真的没有多少理由 – 它们只是编译成不同的字节码。 如果将方法声明为synchronized ,则该同步是方法定义的一部分。 方法中的同步块不是方法定义的一部分 ,而是涉及单独的字节码来获取和释放监视器,如上面的一张海报所示。 严格来说,它们略有不同,但从程序的整体逻辑来看 ,它们是等价的

什么时候重要? 好吧,在大多数现代桌面虚拟机上,几乎没有。 但是例如:

  • VM原则上可以在一种情况下进行优化,但不能在另一种情况下进行优化
  • 有一些JIT编译器优化,其中方法中的字节码数量被作为优化的标准
  • 没有 JIT编译器的VM(现在很少见,但可能在较旧的移动设备上?)将在每次调用时处理更多的字节码

是。 在实例方法上使用synchronized关键字使用’this’作为监视器,在类方法(静态方法)上使用它也使用类’Class对象(Foo.class)。

这样,您可以同步整个方法,同时使用synchronized-block样式将其与另一个方法中的代码片段同步。

我看不到任何function差异 – 两者同步它们的整个方法体(this)。 评论这些不同的人如何certificate他们的陈述是正确的?

它们在function上并不完全相同。 其他代码可以使用reflection来查看您的方法是否具有synchronized修饰符,但无法判断方法是否包含同步块而不读取其字节码。

确定方法是否偶尔同步的能力派上用场。 就个人而言,在面向方面编程中进行同步时,我使用该标志来避免冗余锁定。

 MyObject myObjectA; MyObject myObjectB; public void someMethod() { synchronized (this) { //stuff } } public void someMethodA() { synchronized (myObjectA) { //stuff } } public void someMethodB() { synchronized (myObjectB) { //stuff } } 

在这种情况下:

  • someMethod阻止整个类
  • someMethodA仅阻止myObjectA
  • someMethodB仅阻止myObjectB
  • someMethodAsomeMethodB可以同时调用