import java.lang.management.ManagementFactory; import java.lang.management.ThreadMXBean; import java.util.Date; import java.util.Scanner; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * Example of how a deadlock might be created, and how to detect it. Two threads * are launched, each acquiring the same two resources but in a different order. * A delay is introduced in the first thread before acquiring the second * resource to set up a race condition such that a deadlock *may* be introduced. * The deadlock is not guaranteed to occur; it depends on the length of the * delay, which is controlled by the user executing the program. Empirically, on * my desktop, I've found that values of 100 sometimes are adequate, while * values of 1000+ become increasingly reliable. * * Note that looking for deadlocks with the JMX mechanism used here (ThreadMXBean) is * described in the javadocs as an operation that "might be expensive". As such, * unless you're confident that the cost is not high...I'd recommend not putting * this into operation, rather using it in dev/test environment when trying to * reproduce a situation observed in production where a deadlock occurred. Note * that in production, issuing SIGQUIT (ctl-backslash) will provoke a thread * dump (without killing the process), in which information on deadlocked * threads will also appear. */ public class DeadlockedThreadFinder { // done becomes true when either thread completes; note that if one thread // completes, then the other one will also public boolean done; /** * Launch two threads, each acquiring a lock on two different resources in a * different order. The first thread pauses some time T as a function of the * given delay. * * @param delay is the given delay */ public void createDeadlock(final int delay) { System.out.println("First thread will pause for time T as function of " + delay); // the resources in contention - if threads use the synchronized keyword, // you could use something like the two Object declared (and commented // out) here; else, use the ReentrantLock if in java.util.concurrent // land. // final Object resource1 = new Object(); // final Object resource2 = new Object(); final Lock lock1 = new ReentrantLock(); final Lock lock2 = new ReentrantLock(); // first thread Thread t1 = new Thread() { public void run() { long id = this.getId(); lock1.lock(); // alternately use synchronized (resource1) without // the try-finally block try { System.out.println(id + ": obtained first lock"); // instead of using Thread.sleep(), just create a whole bunch // of expensive objects for (int i = 0; i < delay; i++) { new Date(); } System.out.println(id + " waiting for 2nd lock..."); lock2.lock(); // or use synchronized (resource2) try { System.out.println(id + ": obtained 2nd lock"); } finally { lock2.unlock(); } System.out.println(id + " is done!"); done = true; } finally { lock1.unlock(); } } }; // second thread Thread t2 = new Thread() { public void run() { long id = this.getId(); lock2.lock(); // alternately use synchronized (resource2) without // the try-finally block try { System.out.println(id + ": obtained 2nd lock"); System.out.println(id + " waiting for first lock..."); lock1.lock(); // or use synchronized (resource1) try { System.out.println(id + ": obtained first lock"); } finally { lock1.unlock(); } System.out.println(id + " is done!"); done = true; } finally { lock2.unlock(); } } }; t1.start(); t2.start(); } /** * User must enter an integer that specifies the delay. Values of 10000+ are * likely to cause a deadlock. The larger the value entered, the more likely * the program will loop a few times detecting no deadlock, and then, once * the first thread has satisfied the delay, the program will detect a * deadlock until the end of time or user termination of program, whichever * comes first. */ public static void main(String[] args) throws Exception { // the JMX deadlock finder ThreadMXBean mxbean = ManagementFactory.getThreadMXBean(); // user specifies the delay System.out.print("Enter delay: "); Scanner sc = new Scanner(System.in); // launch the threads DeadlockedThreadFinder finder = new DeadlockedThreadFinder(); finder.createDeadlock(sc.nextInt()); System.out.println("Waiting for either thread to be done..."); do { // the JMX deadlock finder will return null if no deadlock detected. // Note that if the threads are using traditional synchronization (i.e. // using the synchronized keyword), then you could also use the // findMonitorDeadlockedThreads method here; but since the threads // might uplevel to use java.util.concurrent, it's advised to instead // always use findDeadlockedThreads, which will work for either situation. long[] deadlocked = mxbean.findDeadlockedThreads(); if (deadlocked != null) { System.out.print("Deadlocked threads: "); String comma = ""; for (long l : deadlocked) { System.out.print(comma + l); comma = ","; } System.out.println(); } else { System.out.println("No deadlock detected"); } Thread.sleep(1000); } while (!finder.done); // uh, done System.out.println("Done"); } }
Thursday, October 27, 2011
Create and Detect Thread Deadlocks
Just the code:
Subscribe to:
Posts (Atom)