Equivalent code for instance method synchronization in Java

While discussing a Java synchronization question, someone made a comment that the following snippets are not equivalent (and may compile to different bytecodes):

public synchronized void someMethod() {
  //stuff
}

and

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

Are they equivalent?


They are equivalent in function, though the compilers I tested (Java 1.6.0_07 and Eclipse 3.4) generate different bytecode. The first generates:

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

The second generates:

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

(Thanks to ASM for the bytecode printing).

So the difference between them persists to the bytecode level, and it's up to the JVM to make their behavior the same. However, they do have the same functional effect - see the example in the Java Language Specification.

It should be noted, that if the method is overridden in a subclass, that it is not necessarily synchronized - so there is no difference in that respect either.

I also ran a test to block a thread trying access the monitor in each case to compare what their stack traces would look like in a thread dump, and they both contained the method in question, so there is no difference there either.


I made the original comment that the statements are identical.

In both cases, the first thing that happens is that the calling thread will try to acquire the current object's (meaning, this ') monitor.

I don't know about different bytecode, I'll be happy to hear the difference. But in practice, they are 100% identical.

EDIT: i'm going to clarify this as some people here got it wrong. Consider:

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

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

In this case doStuff() in class B still overrides doStuff() in class A even though it is not synchronized.

Synchronized keyword is never part of the contract! Not for subclasses, not for interfaces, not for abstract classes.


I made the original comment. My comment was that they are logically equivalent, but compile to different bytecode .

I didn't add anything else to justify it at the time because there's not much to justify really-- they just do compile to different bytecode. If you declare a method as synchronized, then that synchronization is part of the method's definition. A synchronized block within a method isn't part of the method's definition , but instead involves separate bytecodes to acquire and release the monitor, as one of the posters above has illustrated. Strictly speaking, they're slightly different things, though to the overall logic of your program, they're equivalent .

When does this matter? Well, on most modern desktop VMs, hardly ever. But for example:

  • a VM could in principle make optimisations in one case but not the other
  • there are some JIT compiler optimisations where the number of bytecodes in the method is taken as a criterion for what optimisations to make
  • a VM without a JIT compiler (admittedly few nowadays, but maybe on an older mobile device?) will have more bytecodes to process on each call
  • 链接地址: http://www.djcxy.com/p/76242.html

    上一篇: atomic / volatile / synchronized有什么区别?

    下一篇: Java中实例方法同步的等效代码