![](/img/trans.png)
[英]A Java Threading wait() and Notify() seems to work peculiarly
[英]Java Threading Cyclic Notify() and Wait()
我在Java中有一個代碼,其中兩個對象等待並在一個處理完成時互相通知。 在下面的示例中,並假設沒有語法錯誤,我將簡化代碼(我只是想讓您知道此處的邏輯比語法更重要)。
假設我有對象A,它是具有此偽代碼的線程
class A is Thread {
run() {
while(true) {
wait(); // wait for signal from B
// then do something if signal received
B.signal(); // let B know that we're done and wait again
}
}
}
然后我們在這里B也是一個具有此偽代碼的線程
class B is Thread {
run() {
while(true) {
// Do something
A.signal(); // Let A know to continue processing
wait(); // Wait for signal from A before doing something again
}
}
}
如您所見,這是一個周期。 問題是我遇到了死鎖,這是因為當A完成處理后,它會在等待之前通知B進行工作。但是到通知B時,仍有可能A尚未到達代碼中的wait()和B已經在調用A.signal()並導致死鎖。
如何正確解決此問題? 我想到的解決方案是,當通知B工作時,我將讓B的線程休眠數毫秒,但我認為這不是一個好主意。 任何幫助表示贊賞,在此先感謝。
當您使用notify()時,這應與狀態更改關聯。
使用wait()時,應將其與狀態更改檢查相關聯。
在實際代碼中,您僅應在等待某些內容時等待。
注意:wait()可能會虛假喚醒,這並不意味着調用notify()。 如您所見,如果什么都沒有等待,則notify()不會執行任何操作。
您可以使用BlockingQueue在線程之間傳遞工作/消息,而不是使用此模式。 這具有等待/通知和內置工作的對象。
但是,由於通常需要一個線程來完成工作,因此內置了ExecutorService。 這使您可以將工作傳遞給線程池並收集結果。
簡而言之,您應該使用ExecutorService。
如果A使用B的結果,那么您可以考慮使用BlockingQueue 。
如Javadoc中所述 ,您需要將wait
調用放入檢查條件的循環中。 否則,如果沒有可檢查的條件變量或表達式,則可能由於未在此等待而錯過了通知。
另外,正如其他人指出的那樣,您需要保留正在調用wait
或notify
方法的對象的監視器; 這就是synchronized
關鍵字的作用。
在下面的修復中,條件非常簡單; 這是一個在類A和B中稱為notified
的變量。
另外,為正確起見,A和B需要彼此了解。 在您的代碼中,您似乎正在調用靜態方法。 但是notify
方法需要在實例上調用,因此您需要在B和A中分別保留對A和B實例的引用。
這樣可以解決問題:
class A is Thread {
private B b;
private boolean notified;
public void run() {
while(true) {
synchronized(this) {
while (!notified) {
try {
wait(); // wait for signal from B
} catch (InterruptedException e) {}
}
notified = false;
}
synchronized(b) {
// then do something if signal received
b.notified = true;
b.notify(); // let B know that we're done and wait again
}
}
}
}
class B is Thread {
private A a;
private boolean notified;
public void run() {
while(true) {
synchronized(a) {
// Do something
a.notified = true;
a.notify(); // Let A know to continue processing
}
synchronized(this) {
while (!notified) {
try {
wait(); // Wait for signal from A before doing something again
} catch (InterruptedException e) {}
}
notified = false;
}
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.