//TDrink.java -- Coffee or Tea -- safe Thread, synchronized section
//@CopyLeft by tsaiwn@csie.nctu.edu.tw
public class TDrink{
    private long nTicket = 0, nok=0;
    private String lock = "Only a lock";  // any Object can be a Monitor Lock
    private String goodLock = "another Lock"; // to monitor nok
  public static void main(String[]x) throws Exception{
       new TDrink( );
  } // main
    Tea t1 = new Tea("Chang-3");
    Coffee t2 = new Coffee("ArBian");
    Coffee t3 = new Coffee("GiGi"); Tea t4 = new Tea("Lee-4");
    public TDrink( )  throws Exception{
        t1.start( );
        t2.start( ); t3.start( ); t4.start( );
 /// me and t1, t2, .. are running concurrently
        while(true){
           Thread.sleep(13);
           if(nTicket > 20){  // kill all threads
              t1.shouldDie = true; //t1.stop();
              t2.shouldDie = true; t3.shouldDie = true; t4.shouldDie = true;
              break;
           }
        } // while
        t1.join( ); t2.join( ); t3.join( ); t4.join( ); // wait them die
        System.out.println("\n"+ nok + " cups have gone totally!");
        System.out.println("Thank you and Bye!");
    } // TDrink constructor
 class Coffee extends Thread{
    private volatile boolean shouldDie = false;
    private String uName;  private int total;
    public Coffee(String s) { uName = s; total=0;}
    public void run( ){
        while(true){
           long ntmp, delta;
           synchronized( goodLock ) { ++nok; }  // Critical Section
           synchronized( lock )  // indicates this is a Critical section
           { //++nTicket;
             ntmp = nTicket;  ntmp++;
             //yield( );  // yield the Right to use CPU to other Thread
             delta = 2 + ((int)Math.random( )*988) % 58;
             try { sleep(delta); } catch(InterruptedException e){ }
             for(int i=0; i< delta % 58; ++i);  // delay a while
             nTicket = ntmp;
           }
           try { sleep(1+delta*8 %5); } catch(InterruptedException e){ }
           System.out.println(" "+ ntmp +" Drink Coffee by "+uName); total++;
           if(shouldDie) {
              System.out.println("# "+total + " cups Coffee by "+uName);
              return;
           } // if
        } // while
    } // run
 } // Coffee
 class Tea extends Thread{
    private volatile boolean shouldDie = false;
    private int total;  private String uName;
    public Tea(String s) { uName = s; total=0;}
    public void run( ){
        while(true){  long ntmp;
           synchronized( goodLock )  // comment out this line to test
           { ++nok; }   // this should be protected by synchronized
           synchronized( lock )    // comment out this line to test
           { //++nTicket;
             ntmp = nTicket + 1; 
             yield( );  // yield the Right to use CPU to other Thread
             nTicket = ntmp;
           }
           System.out.println(" "+ ntmp +" Drink Tea by "+uName); total++;
           if(shouldDie) {
              System.out.println("# "+total + " cups Tea by "+uName);
              return;
           }
        } // while
    } // run
 } // Tea
}
