Java多執行緒設計模式(1)

科技小能手發表於2017-11-12

1 執行緒中的幾個方法解釋

Thread.sleep(long 毫秒)

在指定的時間內讓當前執行緒休眠,將控制權交給其他執行緒,休眠的執行緒依舊擁有它所佔用的鎖

Thread.yield();

暫停或者放棄當前正在執行的執行緒,並且執行其他執行緒,但是並沒有釋放該執行緒所擁有的鎖,執行緒放棄後,讓其他相同或者更高執行緒得以執行。

t.join()

A執行緒中等待t執行緒,可以指定一定時間後繼續執行或者無限等待

t.interrupt()

中斷t的執行緒,可以喚醒打斷處於sleepjoinwait狀態下的執行緒,

p.wait()

執行緒可以等待一個它鎖定的物件,在等待的時候,它會釋放此物件的鎖並且暫停進入休眠,它會在時間到期、該執行緒被中斷和物件得到通知之前一直保持休息。直到它得到了其他執行緒的通知,如該物件呼叫notify()notifyAll()的時候才會執行

對於使用wait和notify與notifyAll的時候均要先利用同步程式碼塊或者同步方法獲取該物件的鎖,利用wait後,會首先獲取該物件鎖,然後進入該物件的wait set中,暫停當前的執行緒,釋放該物件的鎖,在該物件的wait set等待著

對於直接wait()就是this.wait(),執行wait()的執行緒會在this的wait set中等待著。

Yield和Sleep區別

       sleep 方法使當前執行中的執行緒睡眠一段時間,進入不可以執行狀態,這段時間的長短是由程式設定的,它只有被吵醒或者睡眠時間到才會繼續執行;

       yield方法使當前執行緒讓出CPU佔有權即時間片,重新排隊,但讓出的時間是不可設定的,該執行緒依然是可執行狀態

       yield()方法對應瞭如下操作:先檢測當前是否有相同優先順序的執行緒處於同可執行狀態,如有,則把CPU的佔有權交給該執行緒,否則繼續執行原來的執行緒,所以yield()方法稱為“退讓”,它把執行機會讓給了同等級的其他執行緒。

sleep 方法允許較低優先順序的執行緒獲得執行機會yield()方法執行時,當前執行緒仍處在執行狀態,它在佇列中等候cpu呼叫,所以說是可執行狀態(注意不是執行狀態),所以不可能讓出較低優先順序的執行緒此時獲取CPU佔有權。在一個執行系統中,如果較高優先順序的執行緒沒有呼叫sleep方法,也沒有受到I/O阻塞,那麼較低優先順序執行緒只能等待所有較高優先順序的執行緒執行結束,方可有機會執行。

yield()只是使當前執行緒重新回到可執行狀態,所有執行yield()的執行緒有可能在進入到可執行狀態後馬上又被執行,所以yield()方法只能使同優先順序的執行緒有執行的機會
2 執行緒的啟動

   執行緒的啟動永遠都是呼叫Start()方法開始的, Thread.start ()方法啟動執行緒,使之進入就緒狀態,當 cpu 分配時間片給該執行緒時,由 JVM 排程執行 run ()方法之所以要startrun方法的原因是,因為 JVM 建立一個單獨的執行緒不同於普通方法的呼叫,啟動一個執行緒是由start 方法完成,start 由本地方法實現,需要顯示地被呼叫。Run方法是真正執行的任務部分,另一個好處就是在於當一個物件需要繼承多類的時候,此時就可以將具體的任務實現了 Runnable 介面,然後傳遞給Thread中,避免因繼承了 Thread 類而造成的 Java 的多繼承問題。

   對於同一個Thread類的例項變數,只能呼叫一次Start方法,一旦呼叫start方法,就會變成結束start狀態,當其再次呼叫start方法的時候,就會出現IllegalThreadStateException,就會進行退讓讓執行緒的啟動不會再次執行。Thread類的start方法採用的就是Balking Pattern模式。

   多執行緒都是針對多個執行緒操作同一個物件下作用的。


3 Single Threaded Execution Pattern

   Single Threaded Execution指的就是“只允許一個執行緒執行”的意思,它表明對於呼叫這個方法或物件的時候必須只能讓一個執行緒來執行。利用synchronized來設定物件的監聽器,在synchronized方法體或者同步塊中。必須要注意synchronized例項方法共享的是類的例項物件的鎖,而synchronized類方法即static synchronized的方法共享的是類的鎖,這兩把鎖完全不同。

   對於一個物件的某一個方法,當有多個執行緒需要訪問的時候,這些執行緒是共享這個物件的所有成員屬性的。執行緒是共享這個物件的記憶體。

   Single Threaded Execution中,作為共享資源的類,即可以被多個執行緒訪問的。有兩種方法,安全方法和非安全方法,所謂的安全方法就是多個執行緒呼叫也不會出現問題。而非安全方法在多個執行緒訪問的過程可能會出現問題。需要對於非安全方法做處理。
適用性:當共享資源類的例項可能被多個執行緒訪問的時候,例項的狀態即屬性會被修改,在多個執行緒中,此時就需要對於對於例項的狀態發生變化的範圍作為臨界區,利用synchronized來保護,實現臨界區間,來監聽多執行緒的訪問。


4 Immutable Pattern

   Immutable Pattern指的就是“有著能夠保證例項的狀態絕不會發生變化更改的類”,再次說明這裡指例項的狀態都是指的是類的成員屬性。所謂的不能發生變化,也就是對於類的狀態只允許賦值一次,且不會給外界提供任何setter方法,並且屬性是private final,一般通過在構造器來對於這些狀態賦值,當然也可以將類宣告為final。利用這種方式,就克服利用共享互斥機制來造成的時間浪費。

   Immutable Pattern參與者是一個欄位值無法更改的類,也沒有任何用來更改欄位值的方法。當Immutable參與者的例項一旦建立後,狀態就固定下來,無法更改了。
適用性:當例項產生後,狀態不再發生變化。例項需要多個執行緒共享,訪問很頻繁的時候。


5 Guarded Suspension Pattern–要等到我準備好再通知你們喲

  Guarded Suspension指的意思是“在多執行緒中,當執行緒訪問某一個資源時候,此時並不適合馬上執行某個操作時,就要求想要執行該操作的執行緒必須等待。”Guarded是“被保護的”,suspension是“暫停”的意思。

  Guarded Suspension要求執行緒必須等待。利用的就是wait,再通過notifyAll來通知所有等待的執行緒。將執行緒要執行某一個操作,必須滿足的條件稱為警戒條件。每個執行緒在執行的時候,如果不滿足警戒條件就必須在等待,只有收到通知後,判斷警戒條件成功後,才能進而執行所要的目的操作。

  常用的警戒條件結構如下:

 public synchronized void methodName()

 {

      while(警戒條件的否定)

          使用wait;//這裡直接在共享類中wait,所有等待的都會進入該類例項的this wait set中等候

     //跳出迴圈,說明滿足警戒條件

      執行目的操作。

  }
注:不能將while替換為if,因為凡是處於等待中的執行緒一旦獲得喚醒,就必須在執行目的操作之前先進行警戒條件的判斷才能進而執行目的操作。必須將捕獲wait的異常包括在while迴圈體中,否則一旦發生異常可能就會進而執行目的操作。這裡的wait也不能換為sleep,因為利用sleep該執行緒會一直擁有它所獲得鎖。

在這裡wait和notify都是隱藏在共享資源中,這樣凡是使用該共享資源的執行緒就不需要考慮這些問題了。

GuardedObject參與者是一個擁有被防衛的方法guardedMethod,一般就是利用synchronized來修飾,線上程執行這個方法的時候,只要滿足警戒條件就會執行,否則就會一直等待。警戒條件會隨著例項的狀態變化而變化。還需要一個更改例項狀態的方法stateChangingMethod,來通知那些等待的執行緒。

一般使用while語句和wait方法來實現guardedMethod,使用notify和notifyAll來實現stateChangingMethod


6 Balking Pattern

 Balking Pattern指的是“多執行緒訪問共享資源時候,當現在不適合進行這個操作,或者沒有必要進行這個操作的時候,此時就會直接放棄進行這個操作而返回”。

 Balking Pattern也是需要警戒條件的。GuardedObject參與者是一個擁有被防衛的方法guardedMethod,一般就是利用synchronized來修飾,線上程執行這個方法的時候,只要滿足警戒條件就會執行,否則就會。警戒條馬上返回,直接退出該方法。警戒條件的成立會隨著例項的狀態變化而變化。還需要一個更改例項狀態的方法stateChangingMethod,來通知那些等待的執行緒。

  警戒條件的結構:

 public synchronized void guardedMethod()

 {

     if(警戒條件否定)

        return ;

       //警戒條件滿足情況

     目的操作

   }
適用性:線上程訪問警戒條件不成立的時候,不需要刻意執行等待的時候,不想一直等待警戒條件成立的時候,或者警戒條件只有第一次成立的時候。注意執行緒的start方法就是利用這種方式的,即只有第一次成立的時候才會呼叫,第二次呼叫就會出錯。




本文轉自 zhao_xiao_long 51CTO部落格,原文連結:http://blog.51cto.com/computerdragon/1201769


相關文章