第三章 Guarded Suspension模式 等我準備好哦
Guarded是被守護、被保衛、被保護的意思。Suspension則是暫停的意思。如果執行現在的處理會造成問題,就讓執行處理的執行緒進行等待。
Guarded Suspension模式通過讓執行緒等待來保證例項的安全性。
示例程式
名字 |
說明 |
Request |
表示一個請求的類 |
RequestQueue |
依次存放請求的類 |
ClientThread |
傳送請求的類 |
ServerThread |
接收請求的類 |
Main |
測試程式行為的類 |
【wait與鎖】
假設執行緒要執行某個例項的wait方法,這時執行緒必須獲取該例項的鎖,在上面的synchronized方法中,wait方法被呼叫時,獲取的就是this的鎖。
執行緒執行this的wait方法後,進入this的等待佇列,並釋放持有的this鎖。
notify、notifyAll或interrupt會讓執行緒退出等待佇列,但在實際地繼續執行處理之前還必須再獲取this的鎖。
【Guarded Suspension模式中登場的角色】
GuardedObject(被守護的物件)
GuardedObject角色是一個持有被守護的方法的類。當執行緒執行GuardedMethod方法時,若守護條件成立,則可以立即執行;若守護條件不成立,就要進行等待,守護條件的成立與否會隨著GuardedObject角色的狀態不同而發生變化。
除了GuardedMethod之外,GuardedObject角色還有可能持有其他改變例項的狀態。
在Java中,GuardedMethod通過while語句和wait方法來實現,stateChangingMethod則通過notify/notifyAll方法來實現。
【拓展思路的要點】
- 附加條件的synchronized
在Single Threaded Execution模式中,只要有一個執行緒進入臨界區,其他執行緒就無法進入,只能等待。
而在Guarded Suspension模式中,執行緒是否等待取決於守護條件。Guarded Suspension模式是在Single Threaded Execution模式的基礎上附加了條件而形成的。
public class RequestQueue {
private final Queue<Request> queue = new LinkedList<Request>();
public synchronized Request getRequest() {
while(queue.peek()==null){
try{
wait();
}catch(InterruptedException e) {}
}
return queue.remove();
}
public synchronized void putRequest(Request request) {
queue.offer(request);
notifyAll();
}
}
- wait與notify/notifyAll的責任【可複用性】
wait/notify只出現在RequestQueue類中,而並未出現在ClientThread、ServerThread、Main類中。Guarded Suspension模式的實現封裝在RequestQueue類中。
這種將wait/notifyAll隱藏起來的做法對RequestQueue類的可複用性來說是很重要的,因為使用RequestQueue的其他類無須考慮wait或notifyAll的問題,只要呼叫方法。
- 使用 java.util.concurrent.LinkedBlockingQueue
java.util.concurrent包中提供了與RequestQueue類功能相同的一個類LinkedBlockingQueue。該類實現了java.util.concurrentBlockingQueue介面。
其中,take方法取隊首元素,put方法向佇列末尾新增元素。當佇列為空時,若呼叫take方法便會執行wait。同時take和put已經考慮了互斥處理。
【相關的設計模式】
Single Threaded Execution模式
“檢查守護條件的部分”和“檢查後修改狀態的部分”都使用了Single Threaded Execution模式。檢查和設定等一連串處理都必須單執行緒執行。這是因為在檢查之後,設定之前,其他執行緒不可以執行檢查。檢查和設定都必須是原子操作。
Blocking模式
在Guarded Suspension模式中,當守護條件不成立時,執行緒會一直等待,直至守護條件成立為止。而在Blocking模式中,執行緒不會等待守護條件成立,而是直接返回。
Producer-Consumer模式
在Producer-Consumer模式中,Producer角色放置資料時,以及Consumer角色獲取資料時,都會使用Guarded Suspension模式。
Future模式
在Future模式中,當執行緒想要獲取目標資訊,而目標資訊還未準備好時,則使用Guarded Suspension模式進行等待。
【小結】
Guarded Suspension模式中存在一個持有狀態物件。該物件只有在自身的狀態適合時,才會允許執行緒執行目標處理。
首先將物件的合適狀態表示為“守護條件”。然後在執行目標處理之前,檢查守護條件是否成立。只有當守護條件成立時,執行緒才會執行目標處理;而在守護條件不成立時,執行緒就會一直等到成立為止。
Java中使用while語句來檢查條件,使用wait方法來執行等待的。當條件發生變化時,使用notify/notifyAll方法發出通知。
【練習題1】
閱讀下面關於示例程式執行的內容,敘述正確的請打√,錯誤請打×
(1)getRequest和putRequest是由不同的執行緒呼叫的。
√答:getRequest由ServerThread呼叫,而putRequest則由ClientThread呼叫。
(2)RequestQueue的例項建立了兩個。
×答:RequestQueue的例項只有Main類建立的那個,該例項由ClientThread和ServerThread共享。
(3)getRequest中的remove方法被呼叫時,queue.peek()!=null的值一定是true。
√答:queue.peek()是守護條件。Guarded Suspension模式會確保執行目標處理時,守護條件一定是成立的。
(4)執行緒呼叫getRequest中的wait方法會釋放鎖,並進入queue的等待序列。
×答:進入的不是queue的等待佇列,而是this的等待佇列。