Can two threads access a synchronized method at the same time?
So can two threads access a synchronized method at the same time?
Yes and no:
Yes, if the method is called on different instances of the class.
No, two threads can't simultaneously call synchronized methods on the same instance of the class. This is the case even if the two threads call different methods (as long as the instance is the same).
Can two threads access a synchronized method at the same time?
It depends on what object instance the two threads are trying to lock on. Two threads cannot access the same synchronized
method on the same object instance. One will get the lock and the other will block until the first thread leaves the method.
In your example, instance methods are synchronized on the object that contains them. In this case, when you call alphonse.bow(...)
you are locking on the alphonse
object. gaston.bow(...)
locks gaston
.
There are a couple of ways that you can get multiple instances of an object to lock on the same object.
You could make the method be
static
andsynchronized
in which case they would lock on the class object itself. There is only one of these objects per class loader.public static synchronized void bow(Friend bower) {
They could both lock on a defined static object. Something like:
private static final Object lockObject = new Object(); ... public void bow(Friend bower) { synchronized (lockObject) { .... } }
- Or you could could pass in the object to lock on if you didn't want to make it static.
Your output could be something like the following:
- the
gaston
thread (may) start first and callsbow(alphonse)
- this locks the
gaston
object and outputs:Gaston: Alphonse has bowed to me!
- it calls
alphonse.bowBack(this)
. - this call locks the
alphonse
object and outputs:Alphonse: Gaston has bowed back to me!
alphonse.bowBack(this)
exits, unlocking thealphonse
object.gaston.bow(alphonse)
exits, unlocking thegaston
object.- then the
gaston
thread exits. - the
alphonse
thread (may) start next and callsbow(gaston)
- this locks the
alphonse
object and outputs:Alphonse: Gaston has bowed to me!
- it calls
gaston.bowBack(this)
. - this call locks the
gaston
object and outputs:Gaston: Alphonse has bowed back to me!
gaston.bowBack(this)
exits, unlocking thegaston
object.alphonse.bow(gaston)
exits, unlocking thealphonse
object.
This could happen in a number of different orders. The alphonse
thread could run first even though it's start()
method gets called at a later time. The only thing that the locks save you from is the calling of alphonse.bow(...)
if alphonse.bowBack(...)
is currently running. As @user988052 pointed out, because each thread locks their own object and then tries to lock the other, you can easily get a deadlock.
I didn't check your code in detail but I think I recognize the typical example as to how to create a deadlock.
However you shouldn't call it just once to try to create the deadlock.
Create threads in a loop and there's a very high probability you'll get your deadlock:
for ( int i = 0; i < 1000; i++ ) {
final Friend alphonse =
new Friend("Alphonse");
final Friend gaston =
new Friend("Gaston");
new Thread(new Runnable() {
public void run() { alphonse.bow(gaston); }
}).start();
new Thread(new Runnable() {
public void run() { gaston.bow(alphonse); }
}).start();
}
Note that you won't deadlock your 2000 threads: only some of them will be deadlocked. You can verify this by taking a threadump of your program/JVM.