Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 479
eljenso Avatar asked Jan 06 '09 16:01

eljenso


People also ask

What are alternatives to synchronization in Java?

Synchronized keyword limitations concurrent. locks package from Java 1.5 introduces a Lock interface defined as an alternative to the synchronized keyword : Lock implementations provide more extensive locking operations than can be obtained using synchronized methods and statements.

How many threads per instance can execute inside a synchronized instance method?

Only one thread can execute inside a synchronized instance method.

Can static synchronized methods and instance synchronized methods exist in the same class?

Synchronized static methods are synchronized on the class object of the class the synchronized static method belongs to. Since only one class object exists in the Java VM per class, only one thread can execute inside a static synchronized method in the same class.


4 Answers

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.

like image 123
Dave L. Avatar answered Oct 21 '22 09:10

Dave L.


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.

like image 41
Yuval Adam Avatar answered Oct 21 '22 09:10

Yuval Adam


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
like image 37
Neil Coffey Avatar answered Oct 21 '22 11:10

Neil Coffey


Yes. Using the synchronized keyword on an instance method uses 'this' as a monitor ,also using it on a class method (static method) uses the class' Class object (Foo.class).

This way you can synchronize entire methods, and in the same time, synchronize it with a code snippet in another method using the synchronized-block style.

like image 2
abyx Avatar answered Oct 21 '22 10:10

abyx