Engineering Full Stack Apps with Java and JavaScript
According to the book Java Concurrency in Practice, there are different types of deadlocks such as Lock ordering deadlocks, Open call deadlocks and Resource deadlocks. All the examples in this note are inspired from the examples given in the book Java Concurrency in Practice.
Lock ordering deadlock is caused when using different order of acquiring locks when locking on multiple objects.
One simple scenario is when one thread executes some code synchronized on object1 and needs to execute code synchronized on object2 still holding the object1 lock. At the same time, a second thread executes some code synchronized to obejct2 and needs to execute code synchronized to object1. In simple terms, thread1 hold object1 lock and wait for object2 lock and thread 2 hold object 2 lock and wait for object 1 lock. Both the threads will keep on waiting for the resource held by the other without releasing the lock they hold.
The solution is also simple: either acquire only one lock at a time or when acquiring multiple locks, acquire them in same order, whenever feasible.
A lock ordering can be a simple one as we saw in http://javajee.com/simple-lock-ordering-deadlock-example (where we can directly see the order of acquiring) or a dynamic one (where the order may be decided by external input), which you will see in a later note.
Here we will see one more simple lock ordering example.
package deadlock;
public class SimpleLockOrderingDeadlock {
final static Object lockObject1 = new Object();
final static Object lockObject2 = new Object();public static void method1() {
synchronized (SimpleLockOrderingDeadlock.lockObject1) // Locking on lockObject1
{System.out.println(Thread.currentThread().getName()
+ ": Got lockObject1. Trying for lockObject2");try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (SimpleLockOrderingDeadlock.lockObject2) // Locking on lockObject2
{
System.out.println(Thread.currentThread().getName()
+ ": Got lockObject2.");}
}
}public static void method2() {
synchronized (SimpleLockOrderingDeadlock.lockObject2) // Locking on lockObject2
{
System.out.println(Thread.currentThread().getName()
+ ": Got lockObject2. Trying for lockObject1");try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (SimpleLockOrderingDeadlock.lockObject1) // Locking on lockObject1
{
System.out.println(Thread.currentThread().getName()
+ ": Got lockObject1.");}
}
}
public static void main(String[] args) {
Thread t1 = new Thread()
{
public void run()
{
SimpleLockOrderingDeadlock.method1();
}
};t1.setName("Thread A");
t1.start();
Thread t2 = new Thread()
{
public void run()
{
SimpleLockOrderingDeadlock.method2();
}
};t2.setName("Thread B");
t2.start();
}
}
The program will deadlock and you can verify it using a thread dump.
You can use jconsole, jvisualvm or jps to get the process id of your program and then run jstack <process-id> to get the thread stack dump.
You can use the same commands for a program running from an eclipse also.
Java Concurrency in Practice by Brian Goetz, David Holmes, DOug Lea, Tim Peierls, Joshua Bloch and Joseph Bowbeer.