while循环在java BlockingQueue实现中

时间:2012-03-23 12:42:02

标签: java blockingqueue

我最近看到了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条件?

2 个答案:

答案 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唤醒了。