This post showed how multiple threads synchronizing on two resources in different order usually leads to a deadlock. An obvious solution is to arrange for all threads to acquire locks in the same order.
Alternatively the synchronized blocks can be replaced by reentrant locks. The tryLock method of the ReentrantLock class is used to acquire a lock, returning immediatly if that lock is held by another thread (and not blocking forever as would be the case when using synchronized).
Example follows – livelock issues not dealt with at this point (ie. both threads, whilst not being blocked, may still not get any job done as they keep colliding when trying to acquire locks).
import java.util.concurrent.locks.ReentrantLock;
public class LockAcquisition {
public static void main (String args[]){
final ReentrantLock lockA = new ReentrantLock();
final ReentrantLock lockB = new ReentrantLock();
new Thread() {
public void run (){
while (1==1) {
try {
System.out.println (this + " acquiring lockA");
if (lockA.tryLock()) {
System.out.println (this + " acquired lockA");
System.out.println (this + " acquiring lockB");
if (lockB.tryLock()){
System.out.println (this + " acquired lockB");
}
}
}
finally {
if (lockB.isHeldByCurrentThread()) lockB.unlock();
if (lockA.isHeldByCurrentThread()) lockA.unlock();
}
}
}
}.start();
new Thread() {
public void run (){
while (1==1) {
try {
System.out.println (this + " acquiring lockB");
if (lockB.tryLock());
System.out.println (this + " acquired lockB");
System.out.println (this + " acquiring lockA");
if (lockA.tryLock()){
System.out.println (this + " acquired lockA");
}
}
finally {
if (lockA.isHeldByCurrentThread()) lockA.unlock();
if (lockB.isHeldByCurrentThread()) lockB.unlock();
}
}
}
}.start();
}
}