First, here's a sample:
public class Deadlock {
static class Friend {
private final String name;
public Friend(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public synchronized void bow(Friend bower) {
System.out.format("%s: %s has bowed to me!%n",
this.name, bower.getName());
bower.bowBack(this);
}
public synchronized void bowBack(Friend bower) {
System.out.format("%s: %s has bowed back to me!%n",
this.name, bower.getName());
}
}
public static void main(String[] args) {
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();
}
}
What I don't get is how the blockage occurs. The main function initiates two threads that each begin their own bows.
What exactly does 'synchronized' block? The same function running for the same object (as I originally thought)? The same function for all objects of the same class? All synchronized functions for the same object? All synchronized functions for all objects of the same class?
Help me out here.
Synchronized methods enable a simple strategy for preventing thread interference and memory consistency errors: if an object is visible to more than one thread, all reads or writes to that object's variables are done through synchronized methods.
When we use a synchronized block, Java internally uses a monitor, also known as monitor lock or intrinsic lock, to provide synchronization. These monitors are bound to an object; therefore, all synchronized blocks of the same object can have only one thread executing them at the same time.
Synchronization is the coordination of events to operate a system in unison. For example, the conductor of an orchestra keeps the orchestra synchronized or in time. Systems that operate with all parts in synchrony are said to be synchronous or in sync—and those that are not are asynchronous.
A Synchronized block is a piece of code that can be used to perform synchronization on any specific resource of the method. A Synchronized block is used to lock an object for any shared resource and the scope of a synchronized block is smaller than the synchronized method.
In Java, each Object
provides the ability for a Thread to synchronize
, or lock, on it. When a method is synchronized, the method uses its object instance as the lock. In your example, the methods bow
and bowBack
are both synchronized
, and both are in the same class Friend
. This means that any Thread executing these methods will synchronize on a Friend
instance as its lock.
A sequence of events which will cause a deadlock is:
alphonse.bow(gaston)
, which is synchronized
on the alphonse
Friend
object. This means the Thread must acquire the lock from this object.gaston.bow(alphonse)
, which is synchronized
on the gaston
Friend
object. This means the Thread must acquire the lock from this object.bowback
and waits for the lock on gaston
to be released.bowback
and waits for the lock on alphonse
to be released.To show the sequence of events in much more detail:
main()
begins to execute in the main Therad (call it Thread #1), creating two Friend
instances. So far, so good.new Thread(new Runnable() { ...
. Thread #2 calls alphonse.bow(gaston)
, which is synchronized
on the alphonse
Friend
object. Thread #2 thus acquires the "lock" for the alphonse
object and enters the bow
method.gaston.bow(alphonse)
, which is synchronized on the gaston
Friend
object. Since no-one has yet acquired the "lock" for the gaston
object instance, Thread #3 successfully acquires this lock and enters the bow
method.bower.bowBack(this);
with bower
being a reference to the instance for gaston
. This is the logical equivalent of a call of gaston.bowBack(alphonse)
. Thus, this method is synchronized
on the gaston
instance. The lock for this object has already been acquired and is held by another Thread (Thread #3). Thus, Thread #2 has to wait for the lock on gaston
to be released. The Thread is put into a waiting state, allowing Thread #3 to execute further.bowback
, which in this instance is logically the same as the call alphonse.bowBack(gaston)
. To do this, it needs to acquire the lock for the alphonse
instance, but this lock is held by Thread #2. This Thread is now put into a waiting state.And you are now in a position where neither Thread can execute. Both Thread #2 and Thread #3 are waiting for a lock to be released. But neither lock can be released without a Thread making progress. But neither thread can make progress without a lock being released.
Thus: Deadlock!
Deadlocks very often depend on a specific sequence of events occurring, which can make then difficult to debug since they can be difficult to reproduce.
Synchronized has two effects:
So in short, it blocks any invocations of synchronised methods on the same object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With