java 為什么wait(),notify(),notifyAll()必須在同步(Synchronized)方法/代碼塊中調用?


wait()
作用:該方法用來將當前線程置入休眠狀態,直到接到通知或被中斷為止。條件:在調用wait()之前,線程必須要獲得該對象的對象級別鎖,即只能在同步方法或同步塊中調用wait()方法。進入wait()方法后,當前線程釋放鎖。在從wait()返回前,線程與其他線程競爭重新獲得鎖。如果調用wait()時,沒有持有適當的鎖,則拋出IllegalMonitorStateException

notify()
作用:喚醒其他休眠的線程中的一個,這個線程由系統確定。在調用前,線程也必須要獲得該對象的對象級別鎖,的如果調用notify()時沒有持有適當的鎖,也會拋出IllegalMonitorStateException


 

先回答問題:

(1)為什么wait()必須在同步(Synchronized)方法/代碼塊中調用?

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

(2)為什么notify(),notifyAll()必須在同步(Synchronized)方法/代碼塊中調用?

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

 

 

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

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

首先,要明白,每個對象都可以被認為是一個"監視器monitor",這個監視器由三部分組成(一個獨占鎖,一個入口隊列,一個等待隊列)(ps:和AQS的state,同步隊列,等待隊列好相似)。注意是一個對象只能有一個獨占鎖,但是任意線程線程都可以擁有這個獨占鎖。

對於對象的非同步方法而言,任意時刻可以有任意個線程調用該方法。(即普通方法同一時刻可以有多個線程調用)

對於對象的同步方法而言,只有擁有這個對象的獨占鎖才能調用這個同步方法。如果這個獨占鎖被其他線程占用,那么另外一個調用該同步方法的線程就會處於阻塞狀態,此線程進入入口隊列。

若一個擁有該獨占鎖的線程調用該對象同步方法的wait()方法,則該線程會釋放獨占鎖,並加入對象的等待隊列;(為什么使用wait()?希望某個變量被設置之后再執行,notify()通知變量已經被設置。)

某個線程調用notify(),notifyAll()方法是將等待隊列的線程轉移到入口隊列,然后讓他們競爭鎖,所以這個調用線程本身必須擁有鎖。

 

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

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

 

下面這個圖是線程的狀態圖,沒有太大關系,可以不看

終於理解了這個圖為什么sleep不釋放鎖,wait釋放鎖

 

https://blog.csdn.net/qq_42145871/article/details/81950949

https://blog.csdn.net/qbz_96/article/details/44461645


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM