问:为啥以下代码会产生死锁
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(); } }
答:
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:
- The first Thread started calls
alphonse.bow(gaston)
, which issynchronized
on thealphonse
Friend
object. This means the Thread must acquire the lock from this object. - The second Thread started calls
gaston.bow(alphonse)
, which issynchronized
on thegaston
Friend
object. This means the Thread must acquire the lock from this object. - The first thread started now calls
bowback
and waits for the lock ongaston
to be released. - The second thread started now calls
bowback
and waits for the lock onalphonse
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 twoFriend
instances. So far, so good.- The main Thread starts its first new Thread (call it Thread #2) with the code
new Thread(new Runnable() { ...
. Thread #2 callsalphonse.bow(gaston)
, which issynchronized
on thealphonse
Friend
object. Thread #2 thus acquires the "lock" for thealphonse
object and enters thebow
method. - A time slice occurs here and the original Thread gets a chance to do more processing.
- The main Thread starts a second new Thread (call it Thread #3), just like the first one. Thread #3 calls
gaston.bow(alphonse)
, which is synchronized on thegaston
Friend
object. Since no-one has yet acquired the "lock" for thegaston
object instance, Thread #3 successfully acquires this lock and enters thebow
method. - A time slice occurs here and Thread #2 gets a chance to do more processing.
- Thread #2 now calls
bower.bowBack(this);
withbower
being a reference to the instance forgaston
. This is the logical equivalent of a call ofgaston.bowBack(alphonse)
. Thus, this method issynchronized
on thegaston
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 ongaston
to be released. The Thread is put into a waiting state, allowing Thread #3 to execute further. - Thread #3 now calls
bowback
, which in this instance is logically the same as the callalphonse.bowBack(gaston)
. To do this, it needs to acquire the lock for thealphonse
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.
原文链接:https://stackoverflow.com/questions/749641/how-does-synchronized-work-in-java