我的回答有一些具体实施的信息。它基于我对 Sun JVM 和其他线程库行为的工作知识。
如果两个生产者线程调用notify,是否可以保证两个不同的等待消费者线程会被唤醒?
不它不是。无法保证会有任何消费者被唤醒。可以保证的是,如果有 2 个线程正在等待,那么 2不同的线程将被放入运行队列。
或者可以是两个notify()
彼此很快触发会导致同一个消费者线程排队等待唤醒两次?
第二号notify()
调用不会导致同一个消费者线程排队两次。然而,它可能会导致一个线程被唤醒,并且可能没有其他线程在等待,因此第二个线程notify()
调用可能什么也不做。当然,线程可能已被唤醒,然后立即返回等待,因此获得第二个notify()
那样称呼,但我认为这不是您所要求的。
java是否有一些原子内部操作可以一次性唤醒线程?
是的。这Thread
代码有许多同步点。一旦线程被通知,它就会被移出wait
队列。未来致电notify()
将调查wait
队列并没有找到线程。
多一个重要的观点。对于生产者/消费者模型,始终确保您正在测试条件while
环形。原因是存在竞争条件,消费者在锁上被阻塞但不等待条件。
synchronized (workQueue) {
// you must do a while here
while (workQueue.isEmpty()) {
workQueue.wait();
}
workQueue.remove();
}
Consumer1
可能正在等待workQueue
. Consumer2
可能会被阻止在synchronized
但在运行队列中。如果有东西被放入workQueue
and workQueue.notify()
叫做。Consumer2
现在被放入运行队列但是behind Consumer1
谁先到。这是一个常见的实现。所以Consumer1
进入 a 将项目从workQueue
that Consumer2
被通知。Consumer2
必须再次测试workQueue
否则为空remove()
会抛出,因为队列再次为空。请参阅此处比赛的更多细节.
同样重要的是要认识到虚假唤醒已被记录下来,因此while
循环可防止线程在没有循环的情况下被唤醒wait()
call.
综上所述,如果您可以通过使用减少生产者/消费者代码BlockingQueue
正如其他答案中所建议的那样,那么您应该这样做。这BlockingQueue
代码已经解决了所有这些问题。