Java deadlock detection

Friday, 8. August 2008

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();
	}
}

Leave a Reply