我们如何使用notifyAll确保唤醒后只有一个线程继续?

时间:2017-10-15 01:50:25

标签: java multithreading concurrency synchronization

来自Programming Language Pragmatics,来自Scott

  

恢复暂停在给定对象上的某个线程   线程必须从a内执行预定义的方法notify   同步语句或引用同一对象的方法。喜欢   等,通知没有参数。在响应通知呼叫时,   语言运行时系统选择暂停的任意线程   对象并使其可运行。如果没有这样的线程,那么   通知是无操作。和Mesa一样,有时可能适合   唤醒在给定对象中等待的所有线程; Java提供了内置功能   为此目的的notifyAll方法。

     

如果线程正在等待多个条件(即,如果它们的等待嵌入在不同的循环中),则无法保证   “正确”的线程将被唤醒。确保适当的线程   醒来后,程序员可能会选择使用notifyAll而不是   通知。 确保唤醒后只有一个线程继续,   第一个线索发现它的状况已经满足必须   以这样的方式修改对象的状态,使其他人觉醒   线程,当它们运行时,将简单地回到睡眠状态。   不幸的是,因为所有等待的线程最终都会重新评估   他们的条件每次都可以运行,这个“解决方案”来   多条件问题可能非常昂贵。

  • 使用notifyAll时,所有唤醒线程都会争用重新获取锁定,但只有一个可以重新获取锁定,然后从wait()返回然后重新评估条件。那么为什么它会说“所有等待线程最终重新评估条件每次其中一个可以运行”?

  • 线程如何重新获取锁并重新检查条件是否成立,“修改对象的状态,以便其他唤醒的线程在运行时,将返回到睡眠“?

感谢。

2 个答案:

答案 0 :(得分:0)

  

那么为什么它会说“所有等待的线程最终会在每次其中一条线路运行时重新评估条件”?

在重新获取并释放锁之后,另一个线程将获取并运行。这将继续下去,直到他们都这样做。

  

重新获取锁定并重新检查条件变为真的线程如何“修改对象的状态,以便其他唤醒的线程在运行时,将简单地重新进入休眠状态”?

所有主题都有类似的内容:

while (condition) {
    wait();
}

notifyAll()调用者在调用它之前会将条件设置为false,然后唤醒的线程将退出while循环,在它返回并释放之前它将执行:

condition = true;

所有其他线程都会被唤醒,检查条件,保持while循环并调用wait()(回去睡觉)。

答案 1 :(得分:0)

此外,您应该使用显式锁定机制,因为它允许您为单个锁定使用多个 conditions and condition queues,这样您就可以使用signal()代替{{ 1}}。而且这有更好的性能和更少的争用。

Condition API