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

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

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


当前回答

看看@xagyg发布的代码。

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

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

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

其他回答

notify() -从对象的等待集中随机选择一个线程,并将其置于BLOCKED状态。对象的等待集中的其余线程仍然处于WAITING状态。

notifyAll() -将所有线程从对象的等待集移动到BLOCKED状态。使用notifyAll()后,共享对象的等待集中没有剩余线程,因为所有线程现在都处于BLOCKED状态,而不是WAITING状态。

BLOCKED—锁定获取阻塞。 WAITING -等待通知(或阻塞连接完成)。

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.

但是(如果我正确理解了这些方法之间的区别),总是只选择一个线程进行进一步的监视采集。

这是不对的。o.notifyAll()唤醒在o.wait()调用中阻塞的所有线程。线程只允许一个接一个地从o.wait()返回,但它们将轮流返回。


简单地说,这取决于线程等待通知的原因。您是想告诉其中一个等待线程发生了什么,还是想同时告诉所有等待线程?

在某些情况下,所有等待线程在等待结束后都可以采取有用的操作。一个例子是一组等待某个任务完成的线程;一旦任务完成,所有等待的线程都可以继续它们的业务。在这种情况下,您可以使用notifyAll()同时唤醒所有等待的线程。

另一种情况,例如互斥锁,只有一个等待线程在被通知后可以做一些有用的事情(在这种情况下获得锁)。在这种情况下,您更愿意使用notify()。如果实现得当,您也可以在这种情况下使用notifyAll(),但是您将不必要地唤醒无法做任何事情的线程。


在很多情况下,等待条件的代码会被写成循环:

synchronized(o) {
    while (! IsConditionTrue()) {
        o.wait();
    }
    DoSomethingThatOnlyMakesSenseWhenConditionIsTrue_and_MaybeMakeConditionFalseAgain();
}

这样,如果一个o.notifyAll()调用唤醒了多个等待线程,并且第一个从o.wait() make返回的线程将条件保持在false状态,那么其他被唤醒的线程将返回等待状态。

这里有一个简单的解释:

您是正确的,无论使用notify()还是notifyAll(),直接结果都是恰好有另一个线程获得监视器并开始执行。(假设一些线程实际上在wait()上阻塞了这个对象,其他不相关的线程并没有占用所有可用的内核,等等。)

假设线程A、B和C正在等待这个对象,线程A得到监视器。区别在于当A释放监视器时发生了什么。如果你使用notify(),那么B和C仍然被阻塞在wait()中:它们不是在监视器上等待,而是在等待通知。当A释放监视器时,B和C仍然在那里等待notify()。

如果使用notifyAll(),则B和C都已进入“等待通知”状态,都在等待获取监视器。当A释放监视器时,B或C将获得它(假设没有其他线程竞争该监视器)并开始执行。