1. 程式人生 > >第三章 Guarded Suspension模式 等我準備好哦

第三章 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方法來實現。

【拓展思路的要點】

  1. 附加條件的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();

     }

}
  1. wait與notify/notifyAll的責任【可複用性】

        wait/notify只出現在RequestQueue類中,而並未出現在ClientThread、ServerThread、Main類中。Guarded Suspension模式的實現封裝在RequestQueue類中。

        這種將wait/notifyAll隱藏起來的做法對RequestQueue類的可複用性來說是很重要的,因為使用RequestQueue的其他類無須考慮wait或notifyAll的問題,只要呼叫方法。

  1. 使用 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的等待佇列。