/** 
 * 
 *   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); 
    }


}