作者:Yujiaao
https://segmentfault.com/a/1190000019962661
它們是在有 synchronized 標記的方法或 synchronized 塊中調用的,因為 wait 和 nodify 需要監視對其調用的 Object。
大多數Java開發人員都知道對象類的 wait(),notify() 和 notifyAll() 方法必須在 Java 中的 synchronized 方法或 synchronized 塊中調用, 但是我們想過多少次, 為什么在 Java 中 wait, notify 和 notifyAll 來自 synchronized 塊或方法?
最近這個問題在Java面試中被問到我的一位朋友,他思索了一下,並回答說: 如果我們不從同步上下文中調用 wait() 或 notify() 方法,我們將在 Java 中收到 IllegalMonitorStateException。
他的回答從實際效果上是正確的,但面試官對這樣的答案不會完全滿意,並希望向他解釋這個問題。面試結束后他和我討論了這個問題,我認為他應該告訴面試官關於 Java 中 wait()和 notify()之間的競態條件,如果我們不在同步方法或塊中調用它們就可能存在。
讓我們看看競態條件如何在 Java 程序中產生。它也是流行的線程面試問題之一。
為什么要等待來自 Java中的 synchronized 方法的 wait方法為什么必須從 Java 中的 synchronized 塊或方法調用 ?
我們主要使用 wait(),notify() 或 notifyAll() 方法用於 Java 中的線程間通信。一個線程在檢查條件后正在等待,例如,在經典的生產者 - 消費者問題中,如果緩沖區已滿,則生產者線程等待,並且消費者線程通過使用元素在緩沖區中創建空間后通知生產者線程。
調用notify() 或 notifyAll() 方法向單個或多個線程發出一個條件已更改的通知,並且一旦通知線程離開 synchronized 塊,正在等待的所有線程開始獲取正在等待的對象鎖定,幸運的線程在重新獲取鎖之后從 wait() 方法返回並繼續進行。
讓我們將整個操作分成幾步,以查看Java 中 wait() 和 notify() 方法之間的競爭條件的可能性,我們將使用Produce Consumer 線程示例更好地理解方案:
-
Producer 線程測試條件(緩沖區是是否已滿)並確認是否需要等待(如果發現緩沖區已滿則需要等待)。
-
Consumer 線程在使用緩沖區中的元素后,設置條件。
-
Consumer 線程調用 notify() 方法; 這是不會被聽到的,因為 Producer 線程還沒有等待。
-
Producer 線程調用 wait() 方法並進入等待狀態。
因此,由於競態條件,我們可能會丟失通知,如果我們使用緩沖區或只使用一個元素,生產線程將永遠等待,你的程序將掛起。
“在Java 同步中等待 notify 和 notifyAll 現在讓我們考慮如何解決這個潛在的競態條件?這個競態條件通過使用 Java 提供的 synchronized 關鍵字和鎖定來解決。為了調用 wait(),notify() 或 notifyAll(),必須獲得對我們調用方法的對象的鎖定。
由於 Java 中的 wait() 方法在等待之前釋放鎖定並在從 wait() 返回之前重新獲取鎖定方法,我們必須使用這個鎖來確保檢查條件(緩沖區是否已滿) 和設置條件 (從緩沖區獲取元素) 是原子的,這可以通過使用 synchronized 方法或塊來實現。
我不確定這是否是面試官實際期待的,但這個我認為至少有意義,請糾正我如果我錯了,請告訴我們是否還有其他令人信服的理由調用 wait(),notify() 或 Java 中的 notifyAll() 方法。
總結一下,我們用 Java 中的 synchronized 方法或 synchronized 塊調用 Java 中的 wait(),notify() 或 notifyAll() 方法來避免:
-
Java 會拋出
IllegalMonitorStateException
,如果我們不調用來自同步上下文的wait(),notify()或者notifyAll()方法。 -
Javac 中 wait 和 notify 方法之間的任何潛在競爭條件。
關注公眾號Java技術棧回復"面試"獲取我整理的2020最全面試題及答案。
推薦去我的博客閱讀更多:
2.Spring MVC、Spring Boot、Spring Cloud 系列教程
3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程
覺得不錯,別忘了點贊+轉發哦!