程式扎記: [OO 設計模式] Gossip@DesignPattern : 多執行緒模式 - Guarded Suspension 模式

標籤

2015年1月16日 星期五

[OO 設計模式] Gossip@DesignPattern : 多執行緒模式 - Guarded Suspension 模式

轉載自 這裡 
前言 : 
考慮這麼一個伺服器,它可以處理來自多個客戶端的服務請求(Request),為了迅速接受客戶的請求,它要維持一個請求佇列,客戶的請求會先儲存至請求佇列 中,服務元件會從緩衝區中取出請求並執行,如請求佇列區中沒有請求,服務元件就等待,直到被通知有新的請求存入請求佇列中,服務元件再度進行請求的執行. 

關於這個描述的一個簡單 UML 順序圖如下所示 : 
 

Guarded Suspension 模式 : 
首先要考慮到,請求佇列會同時被兩個以上的執行緒進行存取,即伺服器執行緒與服務元件執行緒,所以必須對請求佇列進行防護,當請求佇列中沒有請求時,服務元件必須等待直到被通知有新的請求. Guarded Suspension模式強調的是對共用資料的防護,避免共用存取的競爭問題. 以Java來實現這個架構的話如下所示 : 
- Request.java : 
  1. package dp.thds.guardedsuspension;  
  2.   
  3. public interface Request {  
  4.     void execute();  
  5. }  
- RequestQueue.java : 
  1. package dp.thds.guardedsuspension;  
  2.   
  3. import java.util.LinkedList;  
  4.   
  5. public class RequestQueue {  
  6.     private LinkedList requests;  
  7.     RequestQueue() {  
  8.         requests = new LinkedList();  
  9.     }  
  10.   
  11.     synchronized Request get() {  
  12.         while(requests.size() == 0) {  
  13.             try {  
  14.                 wait();  
  15.             }  
  16.             catch(InterruptedException e) {  
  17.                 e.printStackTrace();  
  18.             }  
  19.         }  
  20.         return requests.removeFirst();  
  21.     }  
  22.   
  23.     synchronized void put(Request request) {  
  24.         requests.addLast(request);  
  25.         notifyAll();  
  26.     }  
  27. }  

- Server.java : 模擬 Server 置入請求 
  1. package dp.thds.guardedsuspension;  
  2.   
  3. public class Server implements Runnable {  
  4.     private RequestQueue queue;  
  5.     Server(RequestQueue queue) {  
  6.         this.queue = queue;  
  7.     }  
  8.     public void run() {  
  9.         while(true) {  
  10.             Request request = new Request() {  
  11.                 public void execute() {  
  12.                    System.out.println("執行客戶請求...XD");  
  13.                 }  
  14.             };  
  15.             System.out.printf("\t[Server] Request inqueue...\n");  
  16.             queue.put(request);  
  17.             // 暫停隨機時間  
  18.             try {  
  19.                 Thread.sleep((int) (Math.random() * 500));   
  20.             }  
  21.             catch(InterruptedException e) {  
  22.                 e.printStackTrace();  
  23.             }  
  24.         }  
  25.     }  
  26. }  
- Service.java : 模擬 Service 取得請求並執行 
  1. package dp.thds.guardedsuspension;  
  2.   
  3. public class Service implements Runnable {  
  4.     private RequestQueue queue;  
  5.     private String name;  
  6.     Service(RequestQueue queue, String name) {  
  7.         this.queue = queue;  
  8.         this.name = name;  
  9.     }  
  10.     public void run() {  
  11.         while(true) {  
  12.             System.out.printf("\t[%s] Fetch request...\n", name);  
  13.             Request req = queue.get();  
  14.             System.out.printf("\t[%s] Execute request...\n", name);  
  15.             req.execute();  
  16.             // 暫停隨機時間  
  17.             try {  
  18.                 Thread.sleep((int) (Math.random() * 1000));   
  19.             }  
  20.             catch(InterruptedException e) {  
  21.                 e.printStackTrace();  
  22.             }  
  23.         }  
  24.     }      
  25. }  
一個例子是多人聊天伺服器,請求可能只是一個客戶端送出的聊天訊息,聊天訊息會先存至訊息佇列中,服務元件會不斷的從訊息佇列中取出 聊天訊息並發給客戶端,如果訊息佇列中沒有新訊息,則服務元件就進入等待,直到有一個客戶端發出聊天訊息並存入訊息佇列中,此時服務元件再度被通知,然後再度取出 訊息並進行發送. 

補充說明 : 
[ Java設計模式 ] 多線程設計模式 : Guarded Suspension Pattern (要等到我準備好喔)

沒有留言:

張貼留言

網誌存檔