//TeaOK.java --- using Thread safely --- by tsaiwn@csie.nctu.edu.tw //According to the reference manual in JDK, the function stop( ) is unsafe. //Thus, we should "tell" the thread to die through a volatile variable. //..And, any thread should test the associated variable to see if it should //..finish it's job immediately. public class TeaOK { protected static long nTicket = 0; protected static String lock = "Just a Lock for Critical section"; public static void main(String[]x) throws Exception { Tea t1sub = new Tea(); // note that Tea is not a Thread, .. Thread t1 = new Thread(t1sub,"ArBian"); // wrap it in a Thread Coffee t2 = new Coffee("Chang-3"); Coffee t3 = new Coffee("Lee-4"); t1.start( ); t2.start( ); t3.start( ); // t2 和 t3 都是 Coffee, 因Coffee extends Thread, 故t2, t3也都是 Thread while(true) { Thread.sleep(13); if(nTicket > 18) { // close the store, abort all threads t1sub.shouldDie = true; //Note the usage //t1.stop( ); // t1sub是Tea, 它不是 Thread, 因它只是implements Runnable //注意 t1 是把 t1sub 包成 Thread, 所以可用 t1.start() //但Thread這種東東沒有shouldDie, 因此用 t1.shouldDie 不對 t2.shouldDie = true; t3.shouldDie = true; //t3.stop( ); break; } } // while t1.join( ); t2.join( ); t3.join( ); // wait for them to finish System.out.println("\nThank you and Bye!"); } // main } // class TeaOK class Coffee extends Thread { protected volatile boolean shouldDie = false; public Coffee(String name) {super(name); } //setName for this thread public void run( ) { int total = 0; System.out.println("@ " + getName() + " entered."); while(true) { synchronized(TeaOK.lock) // comment out this line to test { // 故意刪掉上列 synchronized 再run看看就可看出問題 long n = TeaOK.nTicket + 1; print(n); print(" Drink Coffee by "+getName()+"\n"); total++; yield( ); // yield the CPU on purpose! 讓出CPU突顯同步問題 TeaOK.nTicket = n; } // Thread 都應該隨時check主人是否要我們自我了斷, 是就離開 run() if(this.shouldDie == true) break; // return; //以下故意再 delay 一下, 使同時access同一變數的問題更明顯 try{ sleep( (int)(Math.random() *58)); }catch(Exception e){;} } // while System.out.println("== " + getName() + " is leaving... " +total); } // run static void print(String s){ System.out.print(s); } static void print(long n) { if(n<100)print(" "); if(n<10)print(" "); print(" "+n); } } // class Coffee class Tea implements Runnable { // Tea 表面上不是 Thread protected volatile boolean shouldDie = false; public void run( ) { int total = 0; String name = Thread.currentThread( ).getName( ); //Thread 有getName() System.out.println("@@ " + name + " entered."); while(true) { synchronized(TeaOK.lock) //Critical section monitored by TeaOK.lock { //用 TeaOK.lock 確保 Critical section 內只能有一 thread long n = TeaOK.nTicket + 1; Coffee.print(n); Coffee.print(" Drink Tea by "+name+"\n"); total++; Thread.yield( ); // 此例 Tea 不是 Thread 故不能直接寫 yield( ); TeaOK.nTicket = n; // 須 extends Thread 者才是 Thread } if(shouldDie == true) break; // 主人要我死, 我就只好 bye bye try{Thread.sleep((int)(Math.random()*58));}catch(Exception e){;} } // while...注意不是 Thread 者也不能直接用 sleep, 要用 Thread.sleep System.out.println("=-= " + name + " is leaving... "+total); } // run } // class Tea