Why is synchronized block better than synchronized method?
Asked Answered
S

10

109

I have started learning synchronization in threading.

Synchronized method:

public class Counter {

   private static int count = 0;

   public static synchronized int getCount() {
      return count;
   }

   public synchronized setCount(int count) {
      this.count = count;
   }

}

Synchronized block:

public class Singleton {

   private static volatile Singleton _instance;

   public static Singleton getInstance() {
      if (_instance == null) {
         synchronized(Singleton.class) {
            if (_instance == null)
               _instance = new Singleton();
         }
      }
      return _instance;
   }
}

When should I use synchronized method and synchronized block?

Why is synchronized block better than synchronized method ?

Sharper answered 3/1, 2014 at 15:4 Comment(3)
You should also read en.wikipedia.org/wiki/Double-checked_lockingMisdeed
In the first case I would use an AtomicInteger and in the second case I use an enum for a Singleton.Farcical
Where does it say it's better? What is the basis for your question?Scuttle
R
134

It's not a matter of better, just different.

When you synchronize a method, you are effectively synchronizing to the object itself. In the case of a static method, you're synchronizing to the class of the object. So the following two pieces of code execute the same way:

public synchronized int getCount() {
    // ...
}

This is just like you wrote this.

public int getCount() {
    synchronized (this) {
        // ...
    }
}

If you want to control synchronization to a specific object, or you only want part of a method to be synchronized to the object, then specify a synchronized block. If you use the synchronized keyword on the method declaration, it will synchronize the whole method to the object or class.

Ratter answered 3/1, 2014 at 15:6 Comment(6)
Yes same goes for class variables and methods except monitor for corresponding Class object is obtained rather than that of the instance(this).Meteoric
Yes it's different, but there are very good reasons for why you never want to synchronize on this so this answer misses the point a bit imo.Sabbath
@Voo: I strongly disagree that you would never want to synchronize on this. In fact, it's a benefit when you want to call a bunch of synchronized methods in succession. You can synchronize on the object for the duration and don't have to worry about releasing and reacquiring locks for each method call. There are lots of different patterns that can be used for synchronization, and each has its own pros and cons depending on the situation.Ratter
There's absolutely no difference between a synchronized method and a method whose only top-level block is synchronized(someObj), in fact the compiler generates code for synchronized as if someObj==this. So there's no advantage of doing so, but you expose internal details to the outside world which clearly breaks encapsulation. Well there's one advantage: You save about 20 byte.Sabbath
@Sabbath The threading behavior of a class isn't an internal detail. It's part of your codes contract. It's frequently omitted, but whether or not I can use a class in a concurrent environment can be a big part of it's use. The synchronized keyword does leak how you manage threading. I don't consider that bad though as you can change your threading control and remove the keyword without breaking any client code.Highpowered
You can remove it yes (strictly speaking that's wrong too though), but you can't add it without potential breaking changes. Whether the class has to lock internally has nothing to do with the functionality it offers. Yes whether something can be used concurrently is part of the code contract but how it does that is an implementation detail.Sabbath
M
64

The difference is in which lock is being acquired:

  • synchronized method acquires a lock on the whole object. This means no other thread can use any synchronized method in the whole object while the method is being run by one thread.

  • synchronized blocks acquires a lock in the object between parentheses after the synchronized keyword. Meaning no other thread can acquire a lock on the locked object until the synchronized block exits.

So if you want to lock the whole object, use a synchronized method. If you want to keep other parts of the object accessible to other threads, use synchronized block.

If you choose the locked object carefully, synchronized blocks will lead to less contention, because the whole object/class is not blocked.

This applies similarly to static methods: a synchronized static method will acquire a lock in the whole class object, while a synchronized block inside a static method will acquire a lock in the object between parentheses.

Minnaminnaminnie answered 3/1, 2014 at 15:50 Comment(4)
So if I have a synchronised block and a thread is running in it, can another thread go into the object and run a synchronised block somewhere else in the object? If I have a synchronised method and one thread is executing in it, no other thread can execute in that object or only in synchronized areas of the object?Corneliuscornell
IMO, this answer could be misleading to newbies because of the way in which it talks about locking "the whole object." Newbies often get the idea that when an object is "locked," that will prevent other threads from using it. But that's not true at all. The only thing that locking an object prevents is, it prevents other threads from locking the same object at the same time. If thread A locks some object, thread B still can use it and modify it, as long as thread B doesn't also try to lock it.Escargot
Also, if a synchronized method locks "the whole object?" Does that mean that a synchronized block only locks part of the object? I don't think that's what you meant to say, but it would be easy for a newbie to think you were saying it. I think you wanted compare the merits of a class that uses one or more private lock objects for "fine grained" locking vs. a class that uses its own publicly visible instances for "coarse" locking.Escargot
@EvilWashingMachine. If we are using a synchronized block and a thread running in it, then only one thread per object can execute the code within the block and while a thread is running in it, no other thread for the same object can execute any synchronized block(they can enter the method but cannot execute code within the block) or method at that time because the current object is locked. Again in the case of a synchronized method, while a thread is running in it, no other thread for the same object can execute any other synchronized block or method. Object locking means 1 thread/object.Sanguinary
M
62

Although not usually a concern, from a security perspective, it is better to use synchronized on a private object, rather than putting it on a method.

Putting it on the method means you are using the lock of the object itself to provide thread safety. With this kind of mechanism, it is possible for a malicious user of your code to also obtain the lock on your object, and hold it forever, effectively blocking other threads. A non-malicious user can effectively do the same thing inadvertently.

If you use the lock of a private data member, you can prevent this, since it is impossible for a malicious user to obtain the lock on your private object.

private final Object lockObject = new Object();

public void getCount() {
    synchronized( lockObject ) {
        ...
    }
}

This technique is mentioned in Bloch's Effective Java (2nd Ed), Item #70

Musing answered 3/1, 2014 at 15:42 Comment(7)
Doesn't even have to be malicious, it's very easy and innocent looking to use an object you get from somewhere to lock (say because you want to synchronize access to exactly this object). Best to avoid such problemsSabbath
@wolfcastle: Could you explain what a "malicious user of your code" is? How are they being malicious, by messing up their own application?Ratter
@ErickRobertson Image you are providing some kind of service with a public API. If your API exposes some mutable object whose operation depends on locking that object, one malicious client can obtain the object, lock it, then loop forever, holding the lock. This could prevent other clients from being able to operate correctly. It's basically a denial-of-service type attack. So they are not messing up just their own application.Musing
Though it is an old answer, I have a comment on this answer. "It is impossible for a malicious user to obtain the lock on your private object." -- what if the "malicious user" uses a different object in the synchronized block rather than the "your private object"?Amentia
This technique is in item #82 in Effective Java (3rd Edition)Agony
@wolfcastle, in your example, the service must be in the same process as the malicious client. What kind of security architecture is that? If your app has a plugin system, for example, those plugins should likely be run in a separate process.Natashianatassia
@arnobpl, Though your comment now is "old," I have a reply. Two parts: (A) a malicious user has no control over which object your code chooses to lock unless you provide some explicit means for them to do exactly that, and (B) If one thread synchronizes on some object, O, that will have no effect on any other thread that synchronizes on some different object, P.Escargot
D
14

Difference between synchronized block and synchronized method are following:

  1. synchronized block reduce scope of lock, but synchronized method's scope of lock is whole method.
  2. synchronized block has better performance as only the critical section is locked but synchronized method has poor performance than block.
  3. synchronized block provide granular control over lock but synchronized method lock either on current object represented by this or class level lock.
  4. synchronized block can throw NullPointerException but synchronized method doesn't throw.
  5. synchronized block: synchronized(this){}

    synchronized method: public synchronized void fun(){}

Deform answered 2/10, 2017 at 9:56 Comment(1)
What do you mean by synchronized block can throw NullPointerException and syncrhonized method can not, if it happens on syncrhonized method then it will not propagate through logs?Pliske
K
7

Define 'better'. A synchronized block is only better because it allows you to:

  1. Synchronize on a different object
  2. Limit the scope of synchronization

Now your specific example is an example of the double-checked locking pattern which is suspect (in older Java versions it was broken, and it is easy to do it wrong).

If your initialization is cheap, it might be better to initialize immediately with a final field, and not on the first request, it would also remove the need for synchronization.

Kuehnel answered 3/1, 2014 at 15:14 Comment(0)
I
4

synchronized should only be used when you want your class to be Thread safe. In fact most of the classes should not use synchronized anyways. synchronized method would only provide a lock on this object and only for the duration of its execution. if you really wanna to make your classes thread safe, you should consider making your variables volatile or synchronize the access.

one of the issues of using synchronized method is that all of the members of the class would use the same lock which will make your program slower. In your case synchronized method and block would execute no different. what I'd would recommend is to use a dedicated lock and use a synchronized block something like this.

public class AClass {
private int x;
private final Object lock = new Object();     //it must be final!

 public void setX() {
    synchronized(lock) {
        x++;
    }
 }
}
Insurgent answered 3/1, 2014 at 15:24 Comment(1)
Re, "if you really wanna to make your classes thread safe, you should consider making your variables volatile." That's terrible advice. volatile is a highly specialized tool. It's better than locking in a few, specialized cases, but newbies who don't fully understand how to write multi-threaded code often use volatile in entirely inappropriate ways. Despite its apparent simplicity, volatile really is an advanced topic.Escargot
U
4

One classic difference between Synchronized block and Synchronized method is that Synchronized method locks the entire object. Synchronized block just locks the code within the block.

Synchronized method: Basically these 2 sync methods disable multithreading. So one thread completes the method1() and the another thread waits for the Thread1 completion.

class SyncExerciseWithSyncMethod {

    public synchronized void method1() {
        try {
            System.out.println("In Method 1");
            Thread.sleep(5000);
        } catch (Exception e) {
            System.out.println("Catch of method 1");
        } finally {
            System.out.println("Finally of method 1");
        }

    }

    public synchronized void method2() {
        try {
            for (int i = 1; i < 10; i++) {
                System.out.println("Method 2 " + i);
                Thread.sleep(1000);
            }
        } catch (Exception e) {
            System.out.println("Catch of method 2");
        } finally {
            System.out.println("Finally of method 2");
        }
    }
}
Output
-------

In Method 1

Finally of method 1

Method 2 1

Method 2 2

Method 2 3

Method 2 4

Method 2 5

Method 2 6

Method 2 7

Method 2 8

Method 2 9

Finally of method 2

Synchronized block: Enables multiple threads to access the same object at same time [Enables multi-threading].

class SyncExerciseWithSyncBlock {

    public Object lock1 = new Object();
    public Object lock2 = new Object();

    public void method1() {
        synchronized (lock1) {
            try {
                System.out.println("In Method 1");
                Thread.sleep(5000);
            } catch (Exception e) {
                System.out.println("Catch of method 1");
            } finally {
                System.out.println("Finally of method 1");
            }
        }

    }

    public void method2() {

        synchronized (lock2) {
            try {
                for (int i = 1; i < 10; i++) {
                    System.out.println("Method 2 " + i);
                    Thread.sleep(1000);
                }
            } catch (Exception e) {
                System.out.println("Catch of method 2");
            } finally {
                System.out.println("Finally of method 2");
            }
        }
    }

}

Output
-------
In Method 1

Method 2 1

Method 2 2

Method 2 3

Method 2 4

Method 2 5

Finally of method 1

Method 2 6

Method 2 7

Method 2 8

Method 2 9

Finally of method 2
Unpriced answered 18/3, 2020 at 4:9 Comment(2)
Re, "Synchronized method locks the entire object." That could reinforce a common misconception that newbies have about the synchronized concept in Java. Many newbies think that when any one thread has "locked an object," then other threads will be unable to access the same object. But of course, that is not how synchronized works at all. The only thing that synchronized prevents—regardless of whether we're talking about synchronized methods or synchronized blocks or both—is, it prevents two or more threads from being synchronized on the same object at the same time.Escargot
Re, "Synchronized block just locks the code within the block." That also could give newbies not one, but two completely wrong ideas; (1) It could make them think that code can be "locked," and (2) It could make them think that a synchronized block cannot interact with any other synchronized block or method. Code can't be locked. Code doesn't need to be locked. Code is immutable. What needs the protection of synchronized is mutable data. And any two or more synchronized blocks or methods can all work together so long as they all are synchronized on the same instance.Escargot
M
2

In your case both are equivalent!

Synchronizing a static method is equivalent to a synchronized block on corresponding Class object.

In fact when you declare a synchronized static method lock is obtained on the monitor corresponding to the Class object.

public static synchronized int getCount() {
    // ...
}

is same as

public int getCount() {
    synchronized (ClassName.class) {
        // ...
    }
}
Meteoric answered 3/1, 2014 at 15:7 Comment(2)
ok . If I Synchronize a non-static method, then what would be the resultSharper
Then it is per instance or the object you create. Two thread can process the same method in two different Objects independent of each other.Meteoric
R
1

It should not be considered as a question of best for usage, but it really depends on the use case or the scenario.

Synchronized Methods

An entire method can be marked as synchronized resulting an implicit lock on the this reference (instance methods) or class (static methods). This is very convenient mechanism to achieve synchronization.

Steps A thread access the synchronized method. It implicitly acquires the lock and execute the code. If other thread want to access the above method, it has to wait. The thread can't get the lock, will be blocked and has to wait till the lock is released.

Synchronized Blocks

To acquire a lock on an object for a specific set of code block, synchronized blocks are the best fit. As a block is sufficient, using a synchronized method will be a waste.

More specifically with Synchronized Block , it is possible to define the object reference on which are want to acquire a lock.

Respiration answered 5/9, 2017 at 5:59 Comment(0)
S
0

Because lock is expensive, when you are using synchronized block you lock only if _instance == null, and after _instance finally initialized you'll never lock. But when you synchronize on method you lock unconditionally, even after the _instance is initialized. This is the idea behind double-checked locking optimization pattern http://en.wikipedia.org/wiki/Double-checked_locking.

Swithbert answered 3/1, 2014 at 15:27 Comment(1)
What you said is true, but it does not answer to the OP's question. OP muddied the waters by providing two very different code examples, one of which showed the use of double-checked locking to initialize a singleton object, but the actual question was about the relative merits of synchronized blocks in Java vs. synchronized methods.Escargot

© 2022 - 2024 — McMap. All rights reserved.