我最近看到了BlockingQueue的以下enqueue实现 (source)
public synchronized void enqueue(Object item)
throws InterruptedException {
while(this.queue.size() == this.limit) {
wait();
}
if(this.queue.size() == 0) {
notifyAll();
}
this.queue.add(item);
}
为什么while
循环是必要的,while
可以替换为if (this.queue.size() == this.limit)
似乎方法enqueue是同步的,因此一次只有1个线程可以在方法体中执行并调用wait()
。一旦通知线程,它是否可以继续向前而不再检查this.queue.size() == this.limit
条件?
答案 0 :(得分:5)
Object.wait()
上的文档最能说明:
线程也可以在没有被通知,中断或超时的情况下唤醒,即所谓的虚假唤醒。虽然这在实践中很少发生,但应用程序必须通过测试应该导致线程被唤醒的条件来防范它,并且如果条件不满足则继续等待。换句话说,等待应该总是出现在循环中,如下所示:
synchronized (obj) {
while (<condition does not hold>)
obj.wait(timeout);
... // Perform action appropriate to condition
}
答案 1 :(得分:4)
没有。你需要while,因为可能有多个线程在等待队列中的空间打开,而notifyAll()调用将唤醒所有这些线程。
wait()方法实际上释放了同步监视器,以便其他线程可以进行。如果没有,那么试图从队列中删除东西的任何线程也会等待在get()方法中输入synchronized块(例如)。
只有一个等待的线程会看到一个部分空的队列。
实际上,他们都不会;由于一些完全不相关的原因,线程可能已经被notifyAll唤醒了。