class QuizTop {
    Object A = new Object();
    Object B = new Object();
    Object C = B;
    
    class Alpha {
        public void X(int i, int a, int b) throws Exception {
            String tn = Thread.currentThread().getName();
			System.err.println(tn+" enters X");

            if (i > 0) Thread.sleep(i*1000);
            
            synchronized(A) {
			    System.err.println(tn+" enters X.A");
			    if (a > 0) Thread.sleep(a*1000);
			    System.err.println(tn+" exits  X.A");
			}
            
            synchronized(B) {
			    System.err.println(tn+" enters X.B");
			    if (b > 0) Thread.sleep(b*1000);
			    System.err.println(tn+" exits  X.B");
		    }

			System.err.println(tn+" exits  X");
        }
    }
    
    class Beta {
        public void Y(int i, int b, int c) throws Exception {
            String tn = Thread.currentThread().getName();
			System.err.println(tn+" enters Y");
            
            if (i > 0) Thread.sleep(i*1000);

            synchronized(B) {
			    System.err.println(tn+" enters Y.B");
			    if (b > 0) Thread.sleep(b*1000);
			    System.err.println(tn+" exits  Y.B");
			}

            synchronized(C) {
			    System.err.println(tn+" enters Y.C");
			    if (c > 0) Thread.sleep(c*1000);
			    System.err.println(tn+" exits  Y.C");
			}

			System.err.println(tn+" exits  Y");
        }
    }

	public static void main(String[] args) {
        new QuizTop().main();
	}
	
	/* 
	X.B, Y.B and Y.C together form a critical section
	
	X.B and Y.B belong to the same critical section
	t1 enters X.B (0 s) BEFORE t2 enters Y.B (1 s)
	t1 must exit X.B (30 s) BEFORE t2 is allowed to enter Y.B
	                alpha.X(0, 0, 30);
	                beta.Y(1, 10, 1);

	
	X.B and Y.C belong to the same critical section
	t2 enters Y.C (9 s) BEFORE t1 enters X.B (10 s)
	t2 must exit Y.C (30 s) BEFORE t1 is allowed to enter X.B
	                alpha.X(0, 10, 1);
	                beta.Y(0, 9, 21);
    */

	void main() {
	    final Alpha alpha = new Alpha();
	    final Beta beta = new Beta();
	    
	    Thread t1 = new Thread() {
	        public void run() {
	            Thread.currentThread().setName("t1");
	            
        	    try {
	                //alpha.X(0, 0, 30);
	                alpha.X(0, 10, 1);
        	    } catch (Exception ex) {
    	            System.err.println(ex);
	            }
	        }
	    };
	    t1.start();
	    
	    Thread t2 = new Thread() {
	        public void run() {
	            Thread.currentThread().setName("t2");
	            
        	    try {
	                //beta.Y(1, 10, 1);
	                beta.Y(0, 9, 21);
        	    } catch (Exception ex) {
    	            System.err.println(ex);
	            }
	        }
	    };
	    t2.start();
	}
}
