2017-10-15 33 views
0

Programming Language Pragmatics,由Scott我们如何使用notifyAll来确保在唤醒后只有一个线程继续运行?

要恢复被暂停给定对象上的螺纹,其他一些 线程必须执行prede音响奈德方法从指相同对象的 同步语句或方法内通知。像 等待,通知没有参数。为了响应通知调用, 语言运行时系统挑选挂起在 对象上的任意线程并使其可运行。如果没有这样的线程,那么通知是不可操作的。和Mesa一样,有时可能会唤醒所有在给定对象中等待的线程; Java为此提供了一个内置的 notifyAll方法。

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

  • 当使用notifyAll,所有唤醒线程将抗衡重新获取锁,但只有一个可以重新获取锁,然后从wait()返回再重新评估条件。那么为什么说“全部等待线程将结束重新评估其条件每次其中一个可以运行”?

  • 线程是如何重新获得锁并重新检查条件成立的,“修改对象的状态以使其他被唤醒的线程在运行时会简单地返回到睡眠状态“?

谢谢。

+0

'Object.notify()'只唤醒一个线程 –

+0

@Rollback书上说'notifyAll'不'notify'。 – Ben

回答

1

那么为什么会说“所有等待的线程最终都会重新评估它们的条件,每次其中一个线程都可以运行”呢?

它将重新获取并释放锁后,不同的线程将获得并运行。这将继续下去,直到他们都这样做。

线程如何重新获取锁并重新检查条件成为真,“修改对象的状态以使其他被唤醒的线程在运行时会简单地返回到睡觉”?

所有线程都将有类似:

while (condition) { 
    wait(); 
} 

notifyAll()主叫方将设置条件false调用前,然后唤醒线程将退出while循环,并返回之前的版本它会这样做:

condition = true; 

所有其他线程将唤醒,检查车况,留在while循环,并呼吁wait()(回去睡觉)。

+0

谢谢。在你的最后两句话中,唤醒线程如何设置'condition = true',以便它可以让其他唤醒线程回到等待状态?我想知道在唤醒线程可以设置condition = true之前是否有其他唤醒线程可以跳出'while(condition)'循环,因此两个唤醒线程可以继续,这是不正确的。 – Ben

+0

@Ben它们不能因为唤醒线程持有锁,其他线程只有在它释放之后才会唤醒一个线程。 – Oleg

+0

这是我的理解。所有的唤醒线程将从调用中恢复到'wait()'。因为对'wait()'的调用在'synchronized'方法内部,所有唤醒线程都隐式地被唤醒,即在唤醒时自动重新获得'synchronized'方法的隐式锁定,这使得隐式锁定不起作用。所以一个唤醒线程必须通过及时设置'condition = true'来阻止其他唤醒线程继续进行,以防止其他唤醒线程继续。它如何设置'condition = true'来实现? – Ben

1

另外,你应该使用明确的锁定机制,因为它可以让你有多个conditions and condition queues对锁单,这将使您能够使用signal(),而不是signalAll()。而且这样有更好的表现和更少的争用。

Condition API

+0

谢谢。每个'Condition'变量都有自己的条件队列,那么我们总是使用'signal()'而不使用'signalAll()'? 'signalAll()'通知所有等待'Condition'变量的线程吗?我们什么时候使用'signalAll()'? – Ben

+0

这只是取决于多个线程是否正在等待条件,并且您不希望发生跳过通知的情况(如果线程仍然无法继续进行,因为我们假设它正在等待另一个锁,那么很少会发生这种情况),你会使用signalAll唤醒所有线程。这里的要点是有多个条件队列,所以每个锁可以有多个等待设置。 –

相关问题