我的回答有一些特定于实现的信息。它基于我对Sun JVM和其他线程库行为的工作知识。
如果两个生产者线程调用notify,是否保证将唤醒两个不同的正在等待的使用者线程?
不它不是。不能保证会有任何消费者醒来。可以保证的是,如果有2个线程在等待,那么会将2个 不同的 线程放入运行队列。
还是
notify()彼此之间很快触发的两个s导致同一用户线程排队两次唤醒?
否。两次
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和
workQueue.notify()被调用。
Consumer2现在进入运行队列,但 落后于
Consumer1谁先行。这是一个常见的实现。所以,
Consumer1去在将删除的项目
workQueue是
Consumer2被通报的。
Consumer2必须再次测试是否
workQueue为空,否则
remove()将抛出异常,因为队列再次为空。有关比赛的更多详细信息,请参见此处。
同样重要的是要认识到已经记录了虚假
while唤醒,因此该循环可以防止未经
wait()调用而唤醒线程。
综上所述,如果您可以通过使用
BlockingQueue其他答案中建议的减少生产者/消费者代码,则应该这样做。该
BlockingQueue代码已经解决了所有这些问题。



