Is There an Advantage to Use a Synchronized Method Instead of a Synchronized Block

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

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
}

Why is synchronized block better than synchronized method?

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.

What is the difference between a synchronized method and synchronized block in Java?

A synchronized method uses the method receiver as a lock (i.e. this for non static methods, and the enclosing class for static methods). Synchronized blocks uses the expression as a lock.

So the following two methods are equivalent from locking prospective:

synchronized void mymethod() { ... }

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

For static methods, the class will be locked:

class MyClass {
synchronized static mystatic() { ... }

static mystaticeq() {
syncrhonized (MyClass.class) { ... }
}
}

For synchronized blocks, you can use any non-null object as a lock:

synchronized (mymap) {
mymap.put(..., ...);
}

Lock scope

For synchronized methods, the lock will be held throughout the method scope, while in the synchronized block, the lock is held only during that block scope (otherwise known as critical section). In practice, the JVM is permitted to optimize by removing some operations out of the synchronized block execution if it can prove that it can be done safely.

synchronized method vs synchronized block

You've answered the question yourself: use one lock object per method and you're safe.

private final Object lockA = new Object();
private final Object lockB = new Object();
public void methodA() {
synchronized(lockA){
....
}
}
public void methodB() {
synchronized(lockB){
....
}
}

For more advanced locking mechanisms (e.g. ReentrantLock), read Java Concurrency in Practice by Brian Goetz et al. You should also read Effective Java by Josh Bloch, it also contains some items about using synchronized.

What would happen with a synchronized block in a thread which is inside a synchronized method?

Re-entrancy doesn't apply here. The only impact of nesting here is allowing the inner class instances to have access to the enclosing instance (including the lock being used). The two things that are synchronized are called in different threads. The new thread once created will have to get chosen by the scheduler before it can run so even though these are using the same lock it would seem unlikely there would be much overlap between the two.

The thread that calls mySyncMethod acquires the lock on the instance of SyncTest it's using, then it creates a new Thread, starts it, then releases the lock and goes on its way.

Later once the new thread starts it has to acquire the lock on the SyncTest object that started it before it can execute its run method. If the lock on SyncTest is in use by something else (either the thread that just created it, another call to mySyncMethod on the same SyncTest instance, or another thread created by another call to mySyncMethod on the same SyncTest instance) then it would have to wait around to get the lock. Then it does whatever it needs to with the list, gets to the end of the method and releases the lock.

There are a lot of problems here:

  • It's unclear why you need to create your own thread rather than use a pool, or why the creating method needs to synchronize and wait around for the new thread to start before it can release its lock.

  • The lock on the SyncTest object is not encapsulated so other things could be acquiring it, it's unclear what things are contending for the lock.

  • Since the list is defined as a static class member, you have more than one SyncTest object; you're going to have separate threads messing with the same list, but using different locks, so it's hard to understand what the point of locking is.

But what you've shown isn't going to deadlock.

What is different between method synchronized vs object synchronized ?

tl;dr - external synchronization opens you up to attack (intentional or otherwise), and also forces you to lock checking that might not be necessary. Also there's nerdy-good information in at the very bottom of this answer.

A synchronized method is almost identical (see bottom) to synchronizing on this:

synchroinzed void foo() {

}

void foo() {
synchronized(this) {

}
}

By making the method itself not synchronized, you allow yourself to lock on any Object, not just this. I personally would recommend synchronizing on an internal Object, like so

private final Object foolock = new Object();

void foo() {
synchronzied(foolock) {

}
}

The reason is, if you do a synchronized method, which effectively locks this someone else could synchronize on you and lock you out of your Object! Imagine the following:

class FooDoer {
// removed! using synchronized methods instead
//final Object foolock = new Object();

synchronized void foo() {

}
}

// thread 1 - attacker
FooDoer f = new FooDoer();
globalMap.put("TheFoo",f);
synchronized(f) {
while(true); // haha!
}

// thread 2 - victim
FooDoer f = globalMap.get("TheFoo");
f.foo(); // locked, because Thread 1 has locked us out!

It opens yourself up to a denial of service attack. That's not good! By making the lock internal, you as the author of class get to control exactly who can lock what areas of your object and under what terms.

The other issue is that you might not have protected data for checking. For example:

synchronized void foo() {
if(expensiveAccessCheck()) {
update();
}
}

void foo() {
if(expensiveAccessCheck()) {
synchronized(foolock) {
update();
}
}
}

In this scenario, you don't have to make everyone else wait while you sit there spinning your wheels. Perhaps you're scraping data off a URL and then updating. Why make everyone else stay locked out of the data? The lower granularity is better in this case.

Now you may recall I said almost identical earlier. There is a tiny, tiny, tiny difference between the two. A synchronized method will bake the instruction to synchronize right into the method signature in the bytecode. This will make the bytecode 1 byte shorter, because it doesn't need to make the extra call. This might have a small impact because the number of bytes in the method's bytecode is one of the factors in determining whether or not to inline. In spite of this minutia, I highly recommend treating them as the same because this is a micro-optimization that will hardly ever play out as significant in a production setting. It just wouldn't be complete to call it identical when they aren't.

Can synchronized methods serve all purposes which a synchronized block can?

A synchronized method is nothing but syntactic sugar for synchronized(this) {...}.

So the literal answer to your question is "not easily". You would need two different objects where the two synchronized methods are declared, and call one from the other. But it seems like a bad idea.

In general, I question the goal of trying to reduce an explicit synchronized block to a synchronized method. Synchronized blocks are more readable, and let you encapsulate the lock object to prevent undesired lock contention if some other code decides to use the same instance as the lock for some reason.

Also, are you sure you need the kind of fine-grained locking you're trying to do? This seems error-prone... a more straightforward code would synchronize on the same object for any operation on the list.

Synchronization vs Lock

If you're simply locking an object, I'd prefer to use synchronized

Example:

Lock.acquire();
doSomethingNifty(); // Throws a NPE!
Lock.release(); // Oh noes, we never release the lock!

You have to explicitly do try{} finally{} everywhere.

Whereas with synchronized, it's super clear and impossible to get wrong:

synchronized(myObject) {
doSomethingNifty();
}

That said, Locks may be more useful for more complicated things where you can't acquire and release in such a clean manner. I would honestly prefer to avoid using bare Locks in the first place, and just go with a more sophisticated concurrency control such as a CyclicBarrier or a LinkedBlockingQueue, if they meet your needs.

I've never had a reason to use wait() or notify() but there may be some good ones.



Related Topics



Leave a reply



Submit