/** * * This is a simple Manager class which will generate a thread deadlock in Java, * using "synchronized" blocks on a pair of objects. The process is: * * The process is: * * 1. Create two threads, each designed to lock a pair of objects. * 2. Thread1 locks Obj1 and then sleeps a bit. * 3. Thread2 locks Obj2 and then sleeps a bit. * 4. Each thread wakes, and Thread1 tries to lock Obj2 while Thread2 tries to lock Obj1. * Since each object is locked due to the other thread being in a block synchronized * on it, a deadlock occurs. * * In steps 2 & 3, we can either do a Thread.yield(), which normally suffices to cause * the other thread to run, causing a deadlock, or we can do a sleep(10), which * will nearly guarantee it. * * @author James Long (james AT jameslong DOT org) * @version 1.0 10/12/2006 */ class ResourceManager { /** * Ways to yield control from the current thread. * YIELD - do a simple Yield * SLEEP - put the thread to sleep for a period of time */ enum YieldType { YIELD, SLEEP }; /** * Locks one object, yields control, and then locks the other object. * * @param requestor The requesting object (used for display purposes only). * @param o1 The first object to lock. * @param o2 The second object to lock. * @param yt The type of yield to perform after the first lock. * @return Returns void, but only if YIELD is specified, and the scheduler reschedules this thread before the other. * @see ResourceManager.YieldType */ public static void lockTwoObjects(DeadlockGenerator requestor, Object o1, Object o2, YieldType yt) { // Lock object o1 for the duration of this block. synchronized(o1) { System.out.println( requestor.hashCode() + " has locked " + o1.hashCode()); // Yield process control from this thread. This takes a lot of the "luck" out // of causing the deadlock; otherwise you would have to hope there is a context // switch between your two locks in Thread 1, wherein Thread 2 can lock its first. // With the yield/sleep, it's almost guaranteed to happen. if ( yt == YieldType.YIELD) { Thread.yield(); } else { try { Thread.sleep(10000); } catch (InterruptedException e) { System.err.println("Thread was interrupted."); }; } System.out.println( requestor.hashCode() + " wants to lock " + o2.hashCode()); // Lock the second object. synchronized(o2) { // You'd probably do something useful here, in a real program. } System.out.println("Failed to cause deadlock. Try 'java DeadlockGenerator SLEEP' to try to force it"); } } } /** * Implements a thread-based class which will try to use the ResourceManager to lock a pair of * objects. As the main class, it also creates the DeadlockGenerator Threads, and sets them * running. * * @author James Long (james AT jameslong DOT org) * @version 1.0 10/12/2006 */ public class DeadlockGenerator extends Thread { /** * One of the objects to lock. */ private Object o1; /** * One of the objects to lock. */ private Object o2; /** * Which style of yield to use. * @see ResourceManager.YieldType */ private ResourceManager.YieldType m_yield; /** * Main constructor - tells this objects to lock object a, then object b, and stop * by YieldType yt * * @see ResourceManager#YieldType */ public DeadlockGenerator( Object a, Object b, ResourceManager.YieldType yt ) { o1 = a; o2 = b; m_yield = yt; } /** * Main entry point to the program. Creates the DeadlockGenerator threads and * starts them running. * @return Never returns, if all goes well. */ public static void main (String[] args) { Object o1 = new Object(); Object o2 = new Object(); DeadlockGenerator t1 = null; DeadlockGenerator t2 = null; // YieldType.YIELD tells the threads to do a Thread.yield() after // it grabs the first lock. This is usually enough to ensure the second // thread gets a lock before the first thread is reactivated. However, // Yield in no way guarantees which thread runs next. Thus, if you // really want to force the deadlock, switch to SLEEP instead, which // does a 10 second sleep, which should be sufficient. if (args.length > 0 && args[0].equals("SLEEP")) { System.out.println("Using 'SLEEP' method."); t1 = new DeadlockGenerator(o1, o2, ResourceManager.YieldType.SLEEP); t2 = new DeadlockGenerator(o2, o1, ResourceManager.YieldType.SLEEP); } else { System.out.println("Using 'YIELD' method."); t1 = new DeadlockGenerator(o1, o2, ResourceManager.YieldType.YIELD); t2 = new DeadlockGenerator(o2, o1, ResourceManager.YieldType.YIELD); } t2.start(); t1.start(); } /** * This function is called when the thread is started. * * @see java.lang.Thread */ public void run() { ResourceManager.lockTwoObjects(this, o1, o2, m_yield); } }