我正在学习Java中的多线程编程,最困难的部分似乎是使用wait()
,notify()
和notifyAll()
进行线程间通信。
我提到wait()
的官方Javadoc,在这里复制:
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}
我明白当线程t
调用wait()
时,它会立即释放锁,然后等待;但是我无法理解while loop
中的条件是什么意思?线程t
检查while loop
条件是否被某个其他线程修改之前,是否有可能存在机会?
有谁可以告诉我这个condition
是什么以及在while
循环中使用哪些基本内容来检查条件?
答案 0 :(得分:2)
您不仅需要循环它,还要检查循环中的条件。 Java不保证您的线程只能通过notify()/ notifyAll()调用或正确的notify()/ notifyAll()调用来唤醒。由于此属性,无环版本可能适用于您的开发环境,并且意外地在生产环境中失败。
例如,您正在等待某事:
synchronized (theObjectYouAreWaitingOn) {
while (!carryOn) {
theObjectYouAreWaitingOn.wait();
}
}
邪恶的线索出现了:
theObjectYouAreWaitingOn.notifyAll(); 如果邪恶的线程没有/不能使用carryOn,你只需继续等待合适的客户端。
编辑:添加了一些样本。等待可以中断。它抛出InterruptedException,你可能需要在try-catch中包装wait。根据您的业务需求,您可以退出或取消异常并继续等待。
检查下面的一个也是为了更清晰。
等待和通知用于实现[条件变量](http://en.wikipedia.org/wiki/Monitor_(synchronization)#Blocking_condition_variables),因此您需要在继续之前检查您等待的特定谓词是否为真。
答案 1 :(得分:2)
问题是obj
可能会通过obj.notifyAll()
调用所有等待的线程,这些被唤醒的线程将以不确定的顺序进入同步代码块,并操作共享数据。因此,有必要在while
循环中检查条件。
假设你有一个空队列,thread1和thread2正在等待从中获取元素,
synchronized (obj) {
while (queue.isEmpty())
obj.wait();
... // Perform action appropriate to condition
queue.take();
}
在thread3中放入一个元素后,调用obj.notifyAll()
,调用thread1和thread2:
queue.isEmpty()
和wait()
队列中是否有任何元素
试。答案 2 :(得分:1)
condition
循环标题中的while
可以是在boolean
中解析的任何表达式。
在您的示例中,while
循环应暂停执行实际方法,直到某个条件为true
。
假设您的synchronized
方法需要在中午12点执行,并且需要线程安全访问对象obj
然后你while
循环的头部将检查当前时间是否不是12pm。如果这是true
,则该方法无法启动它的实际工作。但是为了防止阻止资源,它将允许其他线程通过调用obj
与obj.wait()
一起使用。
当我们到达下午12点时,while
循环的条件将为false
,并且该线程存在while
循环并执行其余代码。
答案 3 :(得分:1)
我无法理解while循环中的条件是什么意思?
从字面上看,它意味着你正在等待发生的条件的逻辑逆。
在线程t检查while循环中的条件之前是否有机会某个其他线程修改了条件?
假设 1 是构成&#34;条件的变量&#34;只有在obj
上持有锁时,另一个线程才会更新。
因此,在while循环之后的那一点,上面代码中的线程知道条件现在为真,并且在释放锁之前没有其他任何东西会改变它。
现在......很明显......如果某个其他线程要改变组成条件而没有持有锁的变量,那么你担心的可以发生了。但这是一个有缺陷的计划。您有共享变量由不同的线程更新,没有足够的 2 同步。
1 - 线程在调用obj.notify()
或obj.notifyAll()
时必须持有该锁定。 (如果没有,您将获得异常。)但是,如果变量在单独的同步块中更新为通知调用,则保护条件也将起作用。它只是让代码更难理解......
2 - 在这种情况下,将变量声明为volatile
对于保护条件的正确行为是不够的。