Gee*_*eek 65 java multithreading
我已经读过我们应该总是wait()在循环中调用a :
while (!condition) { obj.wait(); }
Run Code Online (Sandbox Code Playgroud)
没有循环它工作正常,为什么会这样?
aka*_*okd 71
您不仅需要循环它,还要检查循环中的条件.Java不保证您的线程只能通过notify()/ notifyAll()调用或正确的notify()/ notifyAll()调用来唤醒.由于此属性,无环版本可能适用于您的开发环境,并且会意外地在生产环境中失败.
例如,您正在等待某事:
synchronized (theObjectYouAreWaitingOn) {
while (!carryOn) {
theObjectYouAreWaitingOn.wait();
}
}
Run Code Online (Sandbox Code Playgroud)
一个邪恶的线程出现了:
theObjectYouAreWaitingOn.notifyAll();
Run Code Online (Sandbox Code Playgroud)
如果邪恶的线程没有/不能搞砸carryOn你只是继续等待适当的客户端.
编辑:添加了一些样本.等待可以中断.它抛出InterruptedException,你可能需要在try-catch中包装wait.根据您的业务需求,您可以退出或取消异常并继续等待.
Tad*_*pec 37
它在Object.wait(long milis)的文档中得到了解答
线程也可以在没有被通知,中断或超时的情况下唤醒,即所谓的虚假唤醒.虽然这在实践中很少发生,但应用程序必须通过测试应该导致线程被唤醒的条件来防范它,并且如果条件不满足则继续等待.换句话说,等待应该总是出现在循环中,如下所示:
synchronized (obj) {
while (<condition does not hold>)
obj.wait(timeout);
... // Perform action appropriate to condition
}
Run Code Online (Sandbox Code Playgroud)
(有关该主题的更多信息,请参阅Doug Lea的"Java中的并发编程(第二版)"(Addison-Wesley,2000)中的第3.2.3节,或Joshua Bloch的"Effective Java Programming Language Guide"中的第50项(Addison-韦斯利,2001年).
Gra*_*ray 14
为什么wait()总是在循环内调用
while循环如此重要的主要原因是线程之间的竞争条件.当然,虚假的唤醒是真实的,对于某些架构来说它们很常见,但竞争条件更可能是while循环的原因.
例如:
synchronized (queue) {
// this needs to be while
while (queue.isEmpty()) {
queue.wait();
}
queue.remove();
}
Run Code Online (Sandbox Code Playgroud)
使用上面的代码,可能有2个消费者线程.当生产者锁定queue要添加到它时,消费者#1可能在synchronized锁定时被阻塞,而消费者#2正在等待queue.当项目被添加到队列notify并由生产者调用时,#2将从等待队列中移动以在锁定上被阻止queue,但它将位于锁定已被阻止的#1使用者后面.这意味着,#1的消费者获得前进首先要求remove()从queue.如果while循环只是一个if,那么当消费者#2在#1之后获得锁并调用时remove(),会发生异常,因为queue现在是空的 - 另一个消费者线程已经删除了该项.仅仅因为它被通知,它需要确保queue由于这种竞争条件仍然是空的.
这有据可查.这是我之前创建的一个网页,它详细解释了竞争条件,并提供了一些示例代码.
我想我得到了@Gray的回答.
让我试着为像我这样的新手重新说明,如果我错了,请求专家纠正我.
消费者同步块:
synchronized (queue) {
// this needs to be while
while (queue.isEmpty()) {
queue.wait();
}
queue.remove();
}
Run Code Online (Sandbox Code Playgroud)
生产者同步块:
synchronized(queue) {
// producer produces inside the queue
queue.notify();
}
Run Code Online (Sandbox Code Playgroud)
假设以给定的顺序发生以下情况:
1)消费者#2进入消费者synchronized区块并等待,因为队列为空.
2)现在,生产者获得锁定queue并插入队列并调用notify().
现在,可以选择消费者#1运行,等待queue锁定synchronized首次进入该块
要么
消费者#2可以选择运行.
3)说,选择消费者#1继续执行.当它检查条件时,它将为真,它将remove()从队列中.
4)说,消费者#2正在从停止执行的地方开始(wait()方法之后的行).如果'while'条件不存在(而不是if条件),它将继续调用remove(),这可能导致异常/意外行为.
因为wait和notify用于实现[条件变量](http://en.wikipedia.org/wiki/Monitor_ ( synchronization)#Blocking_condition_variables)所以你需要检查你正在等待的特定谓词是否为真持续.
| 归档时间: |
|
| 查看次数: |
45278 次 |
| 最近记录: |