2010年10月7日 星期四

[ Java設計模式 ] 多線程設計模式 : Two-Phase Termination Pattern (快把玩具收好, 再去睡覺)

前言 : 

小朋友總是把玩具散落一地. 晚上到了睡覺時間, 媽媽會說 “快把玩具收好, 再去睡覺喔”, 這時小朋友停下來不玩並開始收拾玩具.
這章要學習的是 Two-Phase Termination Pattern. 接下來解釋何謂 Two-Phase Termination, 請參考下圖 :


Two-Phase Termination Pattern 所有參予者 : 
* TerminationRequester (送出終止請求的對象) 參予者 : 
TerminationRequest 參予者會向 Terminator 參予者送出終止請求 (request). 範例程序中 TerminatorRequest 參予者是 Main 類.

* Terminator 參予者 : 
Terminator 參予者會接受終止請求, 實際進行終止處理. Terminator 參予者提供方法讓 TerminationRequest 來呼叫進行終止請求 (shutdownRequest). 當shutdownRequest被調用, Terminator 就會再考慮線程安全情況下進入 [終止處理中] 狀態. 接著在終止處理完畢後, 線程正式結束. 範例程序中, Terminator 參予者是 CountupThread 類.
* Pattern 類別圖 :


範例程序 : 
在這裡要寫的 Two-Phase Termination Pattern 範例程序, 會有一條線程每隔約 500ms 將計數器加一, 而我們約會在 5秒後結束該線程. 
* 類別 CountupThread : 
CountupThread 是一條會不斷遞增數值的線程. counter 成員變量表是計數器, 代碼如下 : 
  1. package dp.thread.ch10;  
  2.   
  3. public class CountupThread extends Thread{  
  4.     private long counter = 0//計數器  
  5.     private volatile boolean shutdownRequested = false// 已經送出終止請求則為 true  
  6.   
  7.     public void shutdownRequest(){  
  8.         shutdownRequested = true;  
  9.         interrupted();  
  10.     }  
  11.   
  12.     public boolean isShutdownRequested(){  
  13.         return shutdownRequested;  
  14.     }  
  15.   
  16.     public final void run(){  
  17.         try{  
  18.             while(!isShutdownRequested()) {  
  19.                 doWork();  
  20.             }  
  21.         }catch(InterruptedException ioe) {  
  22.             ioe.printStackTrace();  
  23.         }finally{  
  24.             doShutdown();  
  25.         }  
  26.     }  
  27.   
  28.     private void doWork() throws InterruptedException {  
  29.         counter++;  
  30.         System.out.println("doWork: counter= "+counter);  
  31.         Thread.sleep(500);  
  32.         if(counter>10000) {  
  33.             doShutdown();  
  34.         }  
  35.     }  
  36.   
  37.     private void doShutdown(){  
  38.         System.out.println("doShutdown: counter= "+counter);  
  39.     }  
  40. }  
* Main 類 : 
Main 類會啟動 CountupThread 線程並約在 5秒後調用shutdownRequest 停止該線程, 代碼如下 : 
  1. package dp.thread.ch10;  
  2.   
  3. public class Main {  
  4.     public static void main(String args[]) {  
  5.         System.out.println("main: BEGIN");  
  6.         try{  
  7.             CountupThread t = new CountupThread();  
  8.             t.start();  //啟動線程  
  9.             Thread.sleep(5000);  
  10.             System.out.println("main: shutdownRequest");  
  11.             t.shutdownRequest(); // 對線程送出終止請求  
  12.             System.out.println("main: join");  
  13.             t.join(); //等待t線程結束.  
  14.         }catch(InterruptedException ioe) {  
  15.             ioe.printStackTrace();  
  16.         }  
  17.         System.out.println("main: END");  
  18.     }  
  19. }  

執行結果 : 
main: BEGIN
doWork: counter= 1
doWork: counter= 2
...(中間省略)...
doWork: counter= 9
doWork: counter= 10
main: shutdownRequest
main: join
doShutdown: counter= 10
main: END


補充說明 : 
@. 不可以使用 Thread 類的 stop 方法: java.lang.Thread 類有一個用來強制結束掉線程的stop 方法. 但是現在stop 已經不被建議使用 (depreciated). 原因是 stop 方法會使實例喪失安全性的保障. 使用 stop 方法時, 線程會拋出 java.lang. ThreadDeath 異常而馬上結束. 即使線程再執行某些 critical process. 請參考如下代碼 : 
  1. class Position {  
  2.   private int x;  
  3.   private int y;  
  4.   public synchronized void setXY(int newX,int newY) {  
  5.     x = newX;  
  6.     y = new Y;  
  7.   }  
  8. }  
Ps. setXY() 是 synchronized 方法, 所以一次只會有一個線程在執行. 也就是說 x 還有 y 值會同時被設定新的值 (原子操作) . 但如果使用 Thread 類的 stop 方法, 剛好又執行到 x=newX; 於是y 值的設定便失敗, 造成 x 與 y 值的不同步. 

@. join 方法與 isAlive方法: 等待指定的線程結束時, 要使用 join 方法, 另外檢查指定的線程現在是否結束了, 可以使用 java.lang.Thread 的 isAlive 方法. 若返回值是true, 該線程還活著. 如果是 false, 表示該線程已經結束了

沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...