1. 程式人生 > >java 為什麼wait(),notify(),notifyAll()必須在同步(Synchronized)方法/程式碼塊中呼叫?

java 為什麼wait(),notify(),notifyAll()必須在同步(Synchronized)方法/程式碼塊中呼叫?

先回答問題:

(1)為什麼wait()必須在同步(Synchronized)方法/程式碼塊中呼叫?

答:呼叫wait()就是釋放鎖,釋放鎖的前提是必須要先獲得鎖,先獲得鎖才能釋放鎖。

(2)為什麼notify(),notifyAll()必須在同步(Synchronized)方法/程式碼塊中呼叫?

答:notify(),notifyAll()是將鎖交給含有wait()方法的執行緒,讓其繼續執行下去,如果自身沒有鎖,怎麼叫把鎖交給其他執行緒呢;(本質是讓處於入口佇列的執行緒競爭鎖)

下面是正文(詳細解釋):

之前一直謹記老師教的wait(),notify(),notifyAll()必須要在Synchronized關鍵中使用,不得其解,現在研究了一下,終於明白了。

首先,要明白,每個物件都可以被認為是一個"監視器monitor",這個監視器由三部分組成(一個獨佔鎖,一個入口佇列,一個等待佇列)。注意是一個物件只能有一個獨佔鎖,但是任意執行緒執行緒都可以擁有這個獨佔鎖。

對於物件的非同步方法而言,任意時刻可以有任意個執行緒呼叫該方法。(即普通方法同一時刻可以有多個執行緒呼叫)

對於物件的同步方法而言,只有擁有這個物件的獨佔鎖才能呼叫這個同步方法。如果這個獨佔鎖被其他執行緒佔用,那麼另外一個呼叫該同步方法的執行緒就會處於阻塞狀態,此執行緒進入入口佇列。

若一個擁有該獨佔鎖的執行緒呼叫該物件同步方法的wait()方法,則該執行緒會釋放獨佔鎖,並加入物件的等待佇列

;(為什麼使用wait()?希望某個變數被設定之後再執行,notify()通知變數已經被設定。)

某個執行緒呼叫notify(),notifyAll()方法是將等待佇列的執行緒轉移到入口佇列,然後讓他們競爭鎖,所以這個呼叫執行緒本身必須擁有鎖。

Synchronized應用舉例:生產者消費者模型

消費者執行緒需要等待直到生產者執行緒完成一次寫入操作。生產者執行緒需要等待消費者執行緒完成一次讀取操作。假設沒有應用Synchronized關鍵字,當消費者執行緒執行wait操作的同時,生產線執行緒執行notify,生產者執行緒可能在等待佇列中找不到消費者執行緒。導致消費者執行緒一直處於阻塞狀態。那麼這個模型就要失敗了。所以必須要加Synchronized關鍵字。

下面這個圖是執行緒的狀態圖,沒有太大關係,可以不看