如果一个人在谷歌上搜索“notify()和notifyAll()之间的区别”,那么会跳出很多解释(撇开javadoc段落)。这都归结于被唤醒的等待线程的数量:notify()中有一个,notifyAll()中有所有线程。

然而(如果我确实理解了这些方法之间的区别),只有一个线程总是被选择用于进一步的监视采集;第一种情况是VM选择的线程,第二种情况是系统线程调度程序选择的线程。程序员不知道它们的确切选择过程(在一般情况下)。

那么notify()和notifyAll()之间有什么有用的区别呢?我遗漏了什么吗?


当前回答

据我所知,以上所有答案都是正确的,所以我要告诉你一些其他的事情。对于生产代码,您确实应该使用java.util.concurrent中的类。在java的并发性方面,它们几乎没有不能为你做的事情。

其他回答

这个答案是xagyg的优秀答案的图形重写和简化,包括eran的评论。

为什么要使用notifyAll,即使每个产品都是针对单个消费者的?

考虑生产者和消费者,简化如下。

制作人:

while (!empty) {
   wait() // on full
}
put()
notify()

消费者:

while (empty) {
   wait() // on empty
}
take()
notify()

假设2个生产者和2个消费者共享一个大小为1的缓冲区。下图描述了一个导致死锁的场景,如果所有线程都使用notifyAll,就可以避免死锁。

每个通知都被标记为被唤醒的线程。

我认为这取决于资源是如何生产和消费的。如果同时有5个工作对象,并且您有5个消费者对象,那么使用notifyAll()唤醒所有线程是有意义的,这样每个线程都可以处理1个工作对象。

如果您只有一个可用的工作对象,那么唤醒所有使用者对象来争夺这个对象有什么意义呢?第一个检查可用工作的线程将得到它,所有其他线程将检查并发现它们无事可做。

我在这里找到了一个很好的解释。简而言之:

The notify() method is generally used for resource pools, where there are an arbitrary number of "consumers" or "workers" that take resources, but when a resource is added to the pool, only one of the waiting consumers or workers can deal with it. The notifyAll() method is actually used in most other cases. Strictly, it is required to notify waiters of a condition that could allow multiple waiters to proceed. But this is often difficult to know. So as a general rule, if you have no particular logic for using notify(), then you should probably use notifyAll(), because it is often difficult to know exactly what threads will be waiting on a particular object and why.

当你调用wait()的“对象”(期望对象锁)、实习生这将释放锁,物体和帮助的其他线程锁在这个“对象”,在这种情况下,将会有超过1线程等待“资源/对象”(考虑到其他线程也发布了等待上面相同的对象,将会有一个线程的方式填补资源/对象并调用通知/ notifyAll)。

在这里,当您(从进程/代码的同一/另一端)发出同一对象的通知时,这将释放一个阻塞和等待的单个线程(不是所有等待的线程——这个释放的线程将由JVM thread Scheduler挑选,对象上的所有锁获取进程与常规进程相同)。

如果只有一个线程共享/处理这个对象,那么可以在wait-notify实现中单独使用notify()方法。

如果您处于基于业务逻辑的多个线程对资源/对象进行读写的情况,那么您应该使用notifyAll()

现在我正在寻找JVM是如何识别和打破等待线程时,我们发出通知()在一个对象…

在这里,所有的醒来都没有多大意义。 Wait notify和notifyall,所有这些都放在拥有对象的监视器之后。如果一个线程处于等待阶段,并且调用了notify,那么这个线程将占用该锁,此时没有其他线程可以占用该锁。所以并发访问根本不能发生。据我所知,只有在锁定对象后才能调用wait notify和notifyall。如果我错了,请指正。

Notify()唤醒在同一对象上调用wait()的第一个线程。

notifyAll()唤醒在同一对象上调用wait()的所有线程。

优先级最高的线程将首先运行。