This is an example from the official concurrency tutorial.
http://download.oracle.com/javase/tutorial/essential/concurrency/deadlock.html
The reason for the deadlock here is that there are two sync methods
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());
}
Say, you have two objects a and b, you call them from thread1 a.bow(b) and from thread2 b.bow(a). When a holds its own lock finished printing and trying to grab b's lock(by calling b.bowBack(a)), b will be holding its own lock, finished printing and trying to grab a's lock. Here comes the deadlock.
How to solve it?
A. Use the same lock for object a and b so that they can have exclusive access to bow(). Previous deadlock situation happens because there is no exclusive access to bow(). To do this, you can pass an explicit lock to both a and b(of course add one constructor for the lock), or you can simply use Class as the lock because both a and b share the same class object.
public void bow(Friend bower) {
synchronized (this.getClass()) {
System.out.format("[%s] %s: %s has bowed to me!%n", Thread.currentThread().getName(),this.name, bower.getName());
bower.bowBack(this);
}
}
public void bowBack(Friend bower) {
synchronized (this.getClass()) {
System.out.format("[%s] %s: %s has bowed back to me!%n", Thread.currentThread().getName(),
this.name, bower.getName());
}
}
B. You can maintain a universal order for getting locks so that no matter which thread access bow(), simultaneously they can only access different parts of it.
public void bow(Friend bower) {
int hashThis = System.identityHashCode(this);
int hashBower = System.identityHashCode(bower);
if (hashThis < hashBower) {
synchronized(this) {
synchronized(bower) {
System.out.printf("[%s]: this: %d, bower: %d\n", Thread.currentThread().getName(), hashThis, hashBower);
System.out.printf("[%s] %s bow to %s\n", Thread.currentThread().getName(), this.getName(), bower.getName());
bower.bowBack(this);
}
}
} else if (hashThis > hashBower) {
synchronized(bower) {
synchronized(this) {
System.out.printf("[%s]222 %s bow to %s\n", Thread.currentThread().getName(), this.getName(), bower.getName());
bower.bowBack(this);
}
}
} else {
synchronized (getClass()) {
System.out.printf("[%s]333 %s bow to %s", Thread.currentThread().getName(), this.getName(), bower.getName());
bower.bowBack(this);
}
}
}
C. Use explicit Lock, this is the approach that is provided by this official tutorial, which should achieve the best performance at practice. One of the advantages is that the tryLock() method can grab the lock or returns false if the lock is held by other threads.
check it out.
http://download.oracle.com/javase/tutorial/essential/concurrency/newlocks.html