sleep & wait | notify | notifyAll

Hoking發表於2016-05-21

摘自:http://www.cnblogs.com/royi123/archive/2013/06/01/3113198.html

一、sleep & wait

1. 兩者來自不同的類(分別是Thread和Object)

2.sleep方法沒有釋放鎖,而wait方法釋放了鎖,使得其他執行緒可以使用同步控制塊或方法

3.wiat只能在同步控制方法或者同步控制塊使用,而sleep可以在任何地方使用

4.sleep必須捕獲異常,而wait不需要

 

二、wait和notify為什麼會封裝在Object類中,而不是像sleep方法在Thread中?

        wait和notify的本質是基於條件物件,而且只能由已經獲得鎖的執行緒呼叫。java的每個Object都有一個隱式鎖,這個隱式鎖關聯一個Condition條件物件,                     執行緒拿到這個隱式所(比如進入synchronized程式碼區域),就可以呼叫wait,語義是Condition條件物件上等待,其他的執行緒可以在這個Condition條件物件上等待 ,等滿足條件之後,就可以呼叫notify或者notifyAll來喚醒所有在此條件物件上等待的執行緒。

 

三、死鎖(產生死鎖的必要條件)

互斥條件:一個資源每次只能被一個程式使用

請求與保持條件:一個程式因請求資源而阻塞時,對已獲得的資源保持不放。

不剝奪條件:程式已獲得的資源,在未使用完之前,不能強制剝奪

迴圈等待條件:若干程式之間形成一種頭尾相接的迴圈資源關係。

         這四個條件時死鎖的必要條件,只有系統發生死鎖,這些條件必然成立,只要上述條件之一不滿足,就不發生死鎖。

 

四、常識

 1.在java中所有執行緒都是同時啟動的,至於什麼時候,哪個先執行,完全看誰先得到CPU的資源。

 2.在java中,每次程式執行至少啟動2個執行緒。一個是main執行緒,一個是垃圾回收執行緒。因為每當使用java命令執行一個類的時候,實際上啟動了一個jvm,每個jvm其實就是在作業系統中啟動了一個執行緒。

 3.理解java編譯器的執行緒處理和jvm。有助於程式設計高效、效能更好的java程式碼。

五、java中wait/notify機制

       notify():喚醒一個處於等待狀態的執行緒,注意的是在呼叫此方法的時候,並不能確切的喚醒某一個等待狀態的執行緒,而是由JVM確定喚醒哪個執行緒,而且不是按優先順序。notify()方法和wait()方法的基本思想是給方法或程式碼塊提供一種相互通訊的方式,而這些方法或者程式碼塊同步於某個特定物件。

       程式碼塊可以呼叫wait()方法來將自身的操作掛起,直到同一個物件上的其他同步方法或同步程式碼塊以某種方式將其改變,並呼叫notfiy()方法來通知此程式碼塊改變已經完成。

        一個執行緒一般會因為它所同步的物件的某個屬性沒有設定,或者某個條件沒有滿足而呼叫wait()方法,這些由另一個執行緒的動作決定。

最簡單的情況可能是資源因為正被另一個執行緒修改而繁忙,還有其他的可能情況。

    通常,多執行緒之間需要協調工作。例如,瀏覽器的一個顯示圖片的執行緒displayThread想要執行顯示圖片的任務,必須等待下載線 程 downloadThread將該圖片下載完畢。如果圖片還沒有下載完,displayThread可以暫停,當downloadThread完成了任務後,再通知displayThread“圖片準備完畢,可以顯示了”,這時,displayThread繼續執行。

以上邏輯簡單的說就是:如果條件不滿足,則等待。當條件滿足時,等待該條件的執行緒將被喚醒。在Java中,這個機制的實現依賴於wait/notify。等待機制與鎖機制是密切關聯的。例如:

synchronized(obj){while(!condition) {obj.wait();}obj.doSomething();} 

當執行緒A獲得了obj鎖後,發現條件condition不滿足,無法繼續下一處理,於是執行緒A就wait()。

在另一執行緒B中,如果B更改了某些條件,使得執行緒A的condition條件滿足了,就可以喚醒執行緒A:

synchronized(obj){condition = true;obj.notify();}

 

需要注意的概念是:

◆呼叫obj的wait(),notify()方法前,必須獲得obj鎖,也就是必須寫在synchronized(obj){...} 程式碼段內。

◆呼叫obj.wait()後,執行緒A就釋放了obj的鎖,否則執行緒B無法獲得obj鎖,也就無法在synchronized(obj) {...} 程式碼段內喚醒A。

◆當obj.wait()方法返回後,執行緒A需要再次獲得obj鎖,才能繼續執行。

◆如果A1,A2,A3都在obj.wait(),則B呼叫obj.notify()只能喚醒A1,A2,A3中的一個(具體哪一個由JVM決定)。

◆obj.notifyAll()則能全部喚醒A1,A2,A3,但是要繼續執行obj.wait()的下一條語句,必須獲得obj鎖,因此,A1,A2,A3只有一個有機會獲得鎖繼續執行,例如A1,其餘的需要等待A1釋放obj鎖之後才能繼續執行。

◆當B呼叫obj.notify/notifyAll的時候,B正持有obj鎖,因此,A1,A2,A3雖被喚醒,但是仍無法獲得obj鎖。直到B退出synchronized塊,釋放obj鎖後,A1,A2,A3中的一個才有機會獲得鎖繼續執行。

 

七、join

         join方法的功能就是使非同步執行的執行緒變成同步執行。也就是說,當呼叫執行緒例項的start方法後,這個方法會立即返回,如果在呼叫start方法後後需要使用一個由這個執行緒計算得到的值,就必須使用join方法。如果不使用join方法,就不能保證當執行到start方法後面的某條語句時,這個執行緒一定會執行完。而使用join方法後,直到這個執行緒退出,程式才會往下執行。例如:你準備洗澡,需要準備的步驟,準備好衣服,沐浴的東西及燒水這些事情,由於燒水耗時太長,如果也放在主執行緒之中,就很浪費資源,所以如果我們另開執行緒去處 理,就會達到很好效果,於是乎在準備好衣服,沐浴的東西之前就去開子執行緒燒水,燒水的過程中主執行緒準備好衣服,沐浴的東西,此時就等待水燒好,然後方可痛 快的洗澡了!!

相關文章