Detecting deadlock is one of common features of Java profiling tools but I haven’t experienced the situation where those tools detect deadlock from code I wrote. In fact, deadlock is hazardous because it is difficult to predict and reproduce.
I wondered under what conditions do profilers detect deadlock and then report it, so I wrote code that reaches deadlock.
package com.grayger.deadlock; public class SimpleDeadlocker { private final static Object OBJ1=new Object(); private final static Object OBJ2=new Object(); private final static int LOOP=100; public void obj1First() { synchronized(OBJ1) { printInfo(“Hold OBJ1″); synchronized(OBJ2) { printInfo(“Hole OBJ2″); } printInfo(“Release OBJ2″); } printInfo(“Release OBJ1″); } public void obj2First() { synchronized(OBJ2) { printInfo(“Hold OBJ2″); synchronized(OBJ1) { printInfo(“Hole OBJ1″); } printInfo(“Release OBJ1″); } printInfo(“Release OBJ2″); } private void printInfo(String info) { System.out.println(Thread.currentThread().getName()+” “+info); } public static void main(String args[]) { final SimpleDeadlocker d=new SimpleDeadlocker(); Thread t1=new Thread(new Runnable() { public void run() { for(int i=0;i<loop;i++)> d.obj1First(); } d.printInfo(“Terminated”); } }, “OBJ1_First”); Thread t2=new Thread(new Runnable() { public void run() { for(int i=0;i<loop;i++)> d.obj2First(); } d.printInfo(“Terminated”); } }, “OBJ2_First”); t1.start(); t2.start(); } }
Above example can be refactored as follows:
package com.grayger.deadlock; public class Deadlocker { private final static int LOOP=100; static class Deadlock1 { private final static Object OBJ1=new Object(); private final static Object OBJ2=new Object(); public void obj1First() { synchronized(OBJ1) { printInfo(“Hold OBJ1″); synchronized(OBJ2) { printInfo(“Hole OBJ2″); } printInfo(“Release OBJ2″); } printInfo(“Release OBJ1″); } } static class Deadlock2 { private final static Object OBJ1=new Object(); private final static Object OBJ2=new Object(); public void obj2First() { synchronized(OBJ2) { printInfo(“Hold OBJ2″); synchronized(OBJ1) { printInfo(“Hole OBJ1″); } printInfo(“Release OBJ1″); } printInfo(“Release OBJ2″); } } public static void printInfo(String info) { System.out.println(Thread.currentThread().getName()+” “+info); } public static void main(String args[]) { final Deadlock1 d1=new Deadlock1(); final Deadlock2 d2=new Deadlock2(); Thread t1=new Thread(new Runnable() { public void run() { for(int i=0;i<loop;i++)> d1.obj1First(); } Deadlocker.printInfo(“Terminated”); } }, “OBJ1_First”); Thread t2=new Thread(new Runnable() { public void run() { for(int i=0;i<loop;i++)> d2.obj2First(); } Deadlocker.printInfo(“Terminated”); } }, “OBJ2_First”); t1.start(); t2.start(); } }
