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

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

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


当前回答

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

其他回答

看看@xagyg发布的代码。

假设两个不同的线程正在等待两个不同的条件: 第一个线程等待buf.size() != MAX_SIZE,第二个线程等待buf.size() != 0。

假设在某一点buf.size()不等于0。JVM调用notify()而不是notifyAll(),并且通知第一个线程(而不是第二个线程)。

第一个线程被唤醒,检查buf.size(),它可能返回MAX_SIZE,然后返回等待。第二个线程没有被唤醒,继续等待,不调用get()。

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

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

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

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

有用的差异:

Use notify() if all your waiting threads are interchangeable (the order they wake up doesn't matter), or if you only ever have one waiting thread. A common example is a thread pool used to execute jobs from a queue--when a job is added, one of threads is notified to wake up, execute the next job and go back to sleep. Use notifyAll() for other cases where the waiting threads may have different purposes and should be able to run concurrently. An example is a maintenance operation on a shared resource, where multiple threads are waiting for the operation to complete before accessing the resource.

总结一下上面的详细解释,用我能想到的最简单的方式,这是由于JVM内置监控器的限制,1)在整个同步单元(块或对象)上获得,2)不区分正在等待/通知/关于的特定条件。

这意味着如果多个线程正在等待不同的条件,并且使用了notify(),所选择的线程可能不是在新满足的条件上取得进展的线程——导致该线程(以及其他当前仍在等待的能够满足条件的线程等)不能取得进展,最终饥饿或程序挂起。

相反,notifyAll()允许所有等待的线程最终重新获得锁并检查各自的条件,从而最终允许执行进程。

因此,notify()只有在任何等待线程被选中时保证允许进程,才可以安全地使用,当同一监视器中的所有线程只检查一个相同的条件时,通常可以满足这一点——在实际应用程序中相当罕见的情况。