Is there an advantage to use a Synchronized Method instead of a Synchronized Block?

293,496

Solution 1

Can anyone tell me the advantage of the synchronized method over the synchronized block with an example? Thanks.

There is not a clear advantage of using synchronized method over the block.

Perhaps the only one ( but I wouldn't call it an advantage ) is you don't need to include the object reference this.

Method:

public synchronized void method() { // blocks "this" from here.... 
    ...
    ...
    ...
} // to here

Block:

public void method() { 
    synchronized( this ) { // blocks "this" from here .... 
        ....
        ....
        ....
    }  // to here...
}

See? No advantage at all.

Blocks do have advantages over methods though, mostly in flexibility because you can use another object as lock whereas syncing the method would lock the entire object.

Compare:

// locks the whole object
... 
private synchronized void someInputRelatedWork() {
    ... 
}
private synchronized void someOutputRelatedWork() {
    ... 
}

vs.

// Using specific locks
Object inputLock = new Object();
Object outputLock = new Object();

private void someInputRelatedWork() {
    synchronized(inputLock) { 
        ... 
    } 
}
private void someOutputRelatedWork() {
    synchronized(outputLock) { 
        ... 
    }
}

Also if the method grows you can still keep the synchronized section separated:

 private void method() {
     ... code here
     ... code here
     ... code here
    synchronized( lock ) { 
        ... very few lines of code here
    }
     ... code here
     ... code here
     ... code here
     ... code here
}

Solution 2

The only real difference is that a synchronized block can choose which object it synchronizes on. A synchronized method can only use 'this' (or the corresponding Class instance for a synchronized class method). For example, these are semantically equivalent:

synchronized void foo() {
  ...
}

void foo() {
    synchronized (this) {
      ...
    }
}

The latter is more flexible since it can compete for the associated lock of any object, often a member variable. It's also more granular because you could have concurrent code executing before and after the block but still within the method. Of course, you could just as easily use a synchronized method by refactoring the concurrent code into separate non-synchronized methods. Use whichever makes the code more comprehensible.

Solution 3

Synchronized Method

Pros:

  • Your IDE can indicate the synchronized methods.
  • The syntax is more compact.
  • Forces to split the synchronized blocks to separate methods.

Cons:

  • Synchronizes to this and so makes it possible to outsiders to synchronize to it too.
  • It is harder to move code outside the synchronized block.

Synchronized block

Pros:

  • Allows using a private variable for the lock and so forcing the lock to stay inside the class.
  • Synchronized blocks can be found by searching references to the variable.

Cons:

  • The syntax is more complicated and so makes the code harder to read.

Personally I prefer using synchronized methods with classes focused only to the thing needing synchronization. Such class should be as small as possible and so it should be easy to review the synchronization. Others shouldn't need to care about synchronization.

Solution 4

The main difference is that if you use a synchronized block you may lock on an object other than this which allows to be much more flexible.

Assume you have a message queue and multiple message producers and consumers. We don't want producers to interfere with each other, but the consumers should be able to retrieve messages without having to wait for the producers. So we just create an object

Object writeLock = new Object();

And from now on every time a producers wants to add a new message we just lock on that:

synchronized(writeLock){
  // do something
}

So consumers may still read, and producers will be locked.

Solution 5

Synchronized method

Synchronized methods have two effects.
First, when one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.

Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads.

Note that constructors cannot be synchronized — using the synchronized keyword with a constructor is a syntax error. Synchronizing constructors doesn't make sense, because only the thread that creates an object should have access to it while it is being constructed.

Synchronized Statement

Unlike synchronized methods, synchronized statements must specify the object that provides the intrinsic lock: Most often I use this to synchronize access to a list or map but I don't want to block access to all methods of the object.

Q: Intrinsic Locks and Synchronization Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. (The API specification often refers to this entity simply as a "monitor.") Intrinsic locks play a role in both aspects of synchronization: enforcing exclusive access to an object's state and establishing happens-before relationships that are essential to visibility.

Every object has an intrinsic lock associated with it. By convention, a thread that needs exclusive and consistent access to an object's fields has to acquire the object's intrinsic lock before accessing them, and then release the intrinsic lock when it's done with them. A thread is said to own the intrinsic lock between the time it has acquired the lock and released the lock. As long as a thread owns an intrinsic lock, no other thread can acquire the same lock. The other thread will block when it attempts to acquire the lock.

package test;

public class SynchTest implements Runnable {  
    private int c = 0;

    public static void main(String[] args) {
        new SynchTest().test();
    }

    public void test() {
        // Create the object with the run() method
        Runnable runnable = new SynchTest();
        Runnable runnable2 = new SynchTest();
        // Create the thread supplying it with the runnable object
        Thread thread = new Thread(runnable,"thread-1");
        Thread thread2 = new Thread(runnable,"thread-2");
//      Here the key point is passing same object, if you pass runnable2 for thread2,
//      then its not applicable for synchronization test and that wont give expected
//      output Synchronization method means "it is not possible for two invocations
//      of synchronized methods on the same object to interleave"

        // Start the thread
        thread.start();
        thread2.start();
    }

    public synchronized  void increment() {
        System.out.println("Begin thread " + Thread.currentThread().getName());
        System.out.println(this.hashCode() + "Value of C = " + c);
//      If we uncomment this for synchronized block, then the result would be different
//      synchronized(this) {
            for (int i = 0; i < 9999999; i++) {
                c += i;
            }
//      }
        System.out.println("End thread " + Thread.currentThread().getName());
    }

//    public synchronized void decrement() {
//        System.out.println("Decrement " + Thread.currentThread().getName());
//    }

    public int value() {
        return c;
    }

    @Override
    public void run() {
        this.increment();
    }
}

Cross check different outputs with synchronized method, block and without synchronization.

Share:
293,496
Warrior
Author by

Warrior

I am a software engineer.I have to learn lot in this field.

Updated on July 14, 2022

Comments

  • Warrior
    Warrior almost 2 years

    Can any one tell me the advantage of synchronized method over synchronized block with an example?

  • Evan
    Evan about 15 years
    The latter can also have merit if not all of the code in foo() needs to be synchronised.
  • OscarRyz
    OscarRyz about 15 years
    This is true, but not what "Warrior" asked: "The advantage of synchronized method" there is none.
  • ef2011
    ef2011 over 12 years
    +1 for being the only one so far to mention that constructors cannot be synchronized. That is, in a constructor you really have only one option: Synchronized blocks.
  • ayyyeee
    ayyyeee about 12 years
    A benefit to the consumer of the API is that using the synchronized keyword in the method declaration also explicitly declares that the method synchronizes on the object instance and is (presumably) thread-safe.
  • ed9w2in6
    ed9w2in6 over 11 years
    so "this" object get locked in less time - so if possible, sync in block rather that the entire method:)
  • ceving
    ceving over 10 years
    Your example is limited to non destructive reads. If the read removes the message from the queue this will fail if it is done at the some time as a producer writes to the queue.
  • justin.hughey
    justin.hughey over 10 years
    I know this is an old question but synchronizing on "this" is considered in some circles to be an anti-pattern. The unintended consequence is that outside of the class someone can lock on an object reference that is equal to "this" and prevent other threads from passing the barriers within the class potentially creating a deadlock situation. Creating a "private final Object = new Object();" variable purely for locking purposes is the often used solution. Here's another question relating directly to this issue.
  • Justin Johnson
    Justin Johnson over 10 years
    I tested your code as directed but C is always 0, then -2024260031 and the only thing that changes it the hash code. What behavior should be seen?
  • Cruncher
    Cruncher about 10 years
    @justin.hughey Yes, but synchronized methods implicitly lock on this
  • justin.hughey
    justin.hughey about 10 years
    @Cruncher, I'm not quite sure what your comment is saying. I was pointing out that you have to be aware of the potentially unintended consequences of locking on this regardless of the mechanism (explicit synchronized(this) vs a synchronized method). Again, please see the question I referenced in my previous comment and read through the solutions. You will see numerous up-voted solutions that detail the dangers synchronizing on this.
  • Cruncher
    Cruncher about 10 years
    @justin.hughey I agree with you completely. It's just that, this answer is showing the difference between sycnhronized(this) vs a synchronized method. Then the point you made was a negative for synchronized(this) which implicitly seems like you're supporting a synchronized method, which has the same problems. I'd also like to add that I essentially, exclusively use private finals for locking purposes.
  • Ross Drew
    Ross Drew about 10 years
    ...Of note as well is that the synchronized block uses a fair bit more bytecode than a synchronized method ibm.com/developerworks/ibm/library/it-haggar_bytecode
  • user207421
    user207421 about 10 years
    Synchronizing with '(this)' does work, and does not 'use the current thread as the synchronizing object', unless the current object is of a class that extends Thread. -1
  • OldPeculier
    OldPeculier almost 10 years
    When you say "stay inside the class" do you mean "stay inside the object", or am I missing something?
  • codepleb
    codepleb over 9 years
    "whereas syncing the method would lock the complete class." This is not correct. It doesn't lock the complete class, but the complete instance. Multiple objects from the same class hold all their own lock. :) Greets
  • corsiKa
    corsiKa over 9 years
    Something interesting about this is that using a synchronized method will cause the generated bytecode to have 1 less instruction, since methods have a synchronized bit baked into their signature. Since the length of the bytecode is a factor in whether a method gets in-lined, moving the block to the method signature could be the difference in decision. In theory anyway. I wouldn't base a design decision on a single bytecode instruction being saved, that seems like a terrible idea. But still, it is a difference. =)
  • Holger
    Holger almost 9 years
    @corsiKa: you save more than one instruction. A synchronized block is implemented using two instructions, monitorenter and monitorexit, plus an exception handler which ensures that monitorexit is called even in the exceptional case. That’s all saved when using a synchronized method.
  • eatSleepCode
    eatSleepCode over 8 years
    If we look at bytecode synchronized method bytecode is more compact and simple, so why its not faster that synchronized block ?
  • Warren Dew
    Warren Dew over 8 years
    @Scrubbie Agreed. Declaring the method synchronized is a more elegant way to communicate the intentions of the programmer. One can always factor out a smaller function if one wants to limit the duration of the lock.
  • Warren Dew
    Warren Dew almost 8 years
    @TrudleR Not only do synchronized methods not lock the whole class, but they don't lock the whole instance either. Unsynchronized methods in the class may still proceed on the instance.
  • codepleb
    codepleb almost 8 years
    @WarrenDew Right. Only the syncronized methods are locked. If there are fields you use within synced methods that are accessed by unsynced methods, you can run into race conditions.
  • Ravindra babu
    Ravindra babu over 7 years
    You should have quoted below articles from which the content has been provided: docs.oracle.com/javase/tutorial/essential/concurrency/… and docs.oracle.com/javase/tutorial/essential/concurrency/…
  • dtc
    dtc about 7 years
    reading this book at the moment... im wondering... if that list was private instead of public and only had the putIfAbsent method, synchronized(this) would be sufficient right? the issue at hand is because the list can be modified outside that ListHelper as well?
  • aarbor
    aarbor about 7 years
    @dtc yea if the list was private and not leaked anywhere else in the class then that would be sufficient, as long as you marked every other method in the class which modifies the list as synchronized also. However, locking the whole method instead of just the List may lead to performance issues if there is a log of code that does not necessarily need to be synchronized
  • dtc
    dtc about 7 years
    that makes sense. thanks so much for answering! tbh, i've found the book quite useful in expanding my knowledge and how to approach multithreading but its also introduced a whole new world of confusion to me
  • Philip Couling
    Philip Couling over 6 years
    @eatSleepCode Note that this is bytecode which is further "compiled" by the JVM. The JVM will add in the necessary monitorenter and monitorexit before running the code.