Guarded Suspension模式(等我準備好哦)
在Single Threaded Execution模式中,只要有一個線程進入臨界區,其他線程就無法進入,只能等待。而在Guarded Suspension模式中,線程是否等待取決於守護條件。Guarded Suspension模式是在Single Threaded Execution模式的基礎上附加了條件而形成的。
如下一段代碼實例:
request用於表示請求,表示ClientThread傳遞給ServerThread的實例
public class Request {
private final String name;
public Request(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public String toString(){
return "[Request"+ name+"]";
}
}
RequestQueue類用於依次存放請求,類中定義了getRequest方法和putRequest方法
getRequest方法會取出最先存放在requestQueue中的一個請求,作爲其返回值。如果一個請求都沒有,那麼就一直等待,直到其他線程執行putRequest
putRequest方法用於添加一個請求。當線程想要向RequestQueue中添加Request實例時,可以調用該實例方法。
public class RequestQueue {
private final Queue<Request> queue = new LinkedList<Request>();
public synchronized Request getRequest(){
while(queue.peek()==null){//守護條件
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return queue.remove();
}
public synchronized void putRequest(Request request){
queue.offer(request);
notifyAll();
}
}
CientThread 類用於表示發送請求的線程。ClientThread持有RequestQueue的實例,並連續調用該實例的putRequest,放入請求,請求的名稱依次爲NO1,NO2.....
爲了錯開發送請求的時間點,使用random隨機生成了0到1000之間的數,來作爲sleep的時間(以毫秒爲單位)
public class ClientThread extends Thread{
private final Random random;
private final RequestQueue requestQueue;
public ClientThread(RequestQueue requestQueue,String name,long seed){
this.requestQueue = requestQueue;
this.random = new Random(seed);
}
public void run(){
for (int i = 0; i < 1000; i++) {
Request request = new Request("No."+i);
System.out.println(Thread.currentThread().getName()+"request:"+request);
requestQueue.putRequest(request);
try {
Thread.sleep(random.nextInt(1000));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
ServerThread類用於表示接收請求的線程。該類持有RequestQueue的實例 (requestQueue).
ServerThread使用getRequest方法接收請求
public class ServerThread extends Thread{
private final Random random;
private final RequestQueue requestQueue;
public ServerThread(RequestQueue requestQueue,String name,long seed){
this.requestQueue = requestQueue;
this.random = new Random(seed);
}
public void run(){
for (int i = 0; i < 1000; i++) {
Request request = requestQueue.getRequest();
System.out.println(Thread.currentThread().getName()+"handles:"+request);
try {
Thread.sleep(random.nextInt(1000));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Main類會首先創建RequestQueue的實例(requestQueue),然後分別創建名爲Alice的實例ClientThread和名爲Boddy的實例ServerThread,並將requestQueue傳給這兩個實例,最後執行start.
public class Main {
public static void main(String[] args) {
RequestQueue requestQueue = new RequestQueue();
new ClientThread(requestQueue, "Alice", 3141592L).start();;
new ClientThread(requestQueue, "Bobby", 6535897L).start();;
}
}
GuardedObject 角色是一個持有被守護的方法的類.當線程執行guardedMethod方法時,如果條件成立,則可以立即執行,當守護條件不成立,則進行等待。
三大特徵:
存在循環
存在條件檢查
因爲某種原因而等待
guarded supension :被守護而暫停執行的含義
guarded wait:被守護而等待
採用LinkedBlockingQueue時,實例程序中的RequestQueue可以被簡化。
take方法用於取出隊首的元素(將隊頭元素出隊,如果隊列空了,一直阻塞,直到隊列不爲空或者線程被中斷),put方法用於向隊列末尾添加元素(在隊尾插入一個元素,如果隊列滿了,一直阻塞,直到隊列不滿了或者線程被中斷)。這兩個方法都進行了封裝。因爲這兩個方法已經考慮了互斥的方法,所以無需聲明爲synchroized方法。
public class RequestQueue {
private final BlockingQueue<Request> queue = new LinkedBlockingQueue<Request>();
public Request getRequest(){
Request req = null;
try {
req = queue.take();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}//取出隊首元素
return req;
}
public void putRequest(Request request){
try {
queue.put(request);//向隊列末尾添加元素
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
LinkedList和LinkedBlockingQueue的比較
對於Guarded Supension模式的總結:
該模式存在一個持有狀態的對象,只有在這個對象的狀態滿足條件的情況下,纔會允許現在執行目標處理。所以,我們先將這個對象的滿足條件作爲它的“守護條件”,然後,在執行這個目標處理之前,檢查守護條件是否成立,只有當守護條件成立時,線程纔會執行目標處理,而當守護條件不成立時,線程就會一直等到成立爲止,使用while條件嵌套檢查條件,wait()執行等待,使用notifyAll()方法進行通知。這就是Guarded Suspension模式。