![](/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.