考慮這麼一個伺服器,它可以處理來自多個客戶端的服務請求(Request),為了迅速接受客戶的請求,它要維持一個請求佇 列,客戶的請求會先儲存至請求佇列 中,服務元件會從緩衝區中取出請求並執行,如請求佇列區中沒有請求,服務元件就等待,直到 被通知有新的請求存入請求佇列中,服務元件再度進行請求的執行。
關於這個描述的一個簡單 UML 順序圖如下所示:
首先要考慮到,請求佇列會同時被兩個以上的執行緒進行存取,即 伺服器執行緒與服務元件執行緒,所以必須對請求佇列進行防護,當請求佇列中 沒有請求時,服務元件必須等待直到被通知有新的請求。
Guarded Suspension模式強調的是對共用資料的防護,避免共用存取的競爭問題。以Java來實現這個架構的話如下所示:
import java.util.*;
interface Request {
void execute();
}
class RequestQueue {
private LinkedList<Request> requests;
RequestQueue() {
requests = new LinkedList<Request>();
}
synchronized Request get() {
while(requests.size() == 0) {
try {
wait();
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
return requests.removeFirst();
}
synchronized void put(Request request) {
requests.addLast(request);
notifyAll();
}
}
// 模擬 Server 置入請求
class Server implements Runnable {
private RequestQueue queue;
Server(RequestQueue queue) {
this.queue = queue;
}
public void run() {
while(true) {
Request request = new Request() {
public void execute() {
System.out.println("執行客戶請求...XD");
}
};
queue.put(request);
// 暫停隨機時間
try {
Thread.sleep((int) (Math.random() * 3000));
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
// 模擬 Service 取得請求並執行
class Service implements Runnable {
private RequestQueue queue;
Service(RequestQueue queue) {
this.queue = queue;
}
public void run() {
while(true) {
queue.get().execute();
// 暫停隨機時間
try {
Thread.sleep((int) (Math.random() * 3000));
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Main {
public static void main(String[] args) {
RequestQueue queue = new RequestQueue();
(new Thread(new Server(queue))).start();
(new Thread(new Service(queue))).start();
}
}
如果使用Python來示範:
import threading
import time
import random
class RequestQueue:
def __init__(self):
self.requests = []
self.condition = threading.Condition()
def get(self):
self.condition.acquire()
while not self.requests:
self.condition.wait()
request = self.requests.pop(0)
self.condition.release()
return request
def put(self, request):
self.condition.acquire()
self.requests.append(request)
self.condition.notify()
self.condition.release()
class Server(threading.Thread):
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
def run(self):
while True:
request = lambda: print("執行客戶請求...XD")
self.queue.put(request)
time.sleep(int(random.random() * 3))
class Service(threading.Thread):
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
def run(self):
while True:
self.queue.get()()
time.sleep(int(random.random() * 3))
queue = RequestQueue()
Server(queue).start()
Service(queue).start()
while True:
try:
time.sleep(1)
except KeyboardInterrupt:
exit()
一個例子是多人聊天伺服器,請求可能只是一個客戶端送出的聊天訊息,聊天訊息會先存至訊息佇列中, 服務元件會不斷的從訊息佇列中取出 聊天訊息並發給客戶端,如果訊息佇列中沒有新訊息,則服務元件就進入等待,直到有一個客戶 端發出聊天訊息並存入訊息佇列中,此時服務元件再度被通知,然後再度取出 訊息並進行發送。