Java 阻塞队列混乱

Java BlockingQueue confusion

我目前正在阅读有关 Java BlockingQueue 的文章,许多网站都提供了这个示例,用于简单实现 BlockingQueue。代码很简单,但我有点困惑。例如,假设我们填满了队列,然后我们尝试再入队 3 次。这将使 3 个线程等待。那么当我们调用dequeue时,dequeue方法中的代码会进入第二个if语句,它会通知所有线程。这不就意味着等待的3个线程都会往队列中添加节点吗?这意味着我们将比限制多 2 个节点?我很确定我在这里误解了一些东西,所以我可以使用一些小的解释。

public class BlockingQueue {

  private List queue = new LinkedList();
  private int  limit = 10;

  public BlockingQueue(int limit){
    this.limit = limit;
  }


  public synchronized void enqueue(Object item)
  throws InterruptedException  {
    while(this.queue.size() == this.limit) {
      wait();
    }
    this.queue.add(item);
    if(this.queue.size() == 1) {
      notifyAll();
    }
  }


  public synchronized Object dequeue()
  throws InterruptedException{
    while(this.queue.size() == 0){
      wait();
    }
    if(this.queue.size() == this.limit){
      notifyAll();
    }

    return this.queue.remove(0);
  }

}

没有,只有一个会加一个节点。请注意,您在 enqueue 中的 wait 调用在一个循环中:

    while(this.queue.size() == this.limit) {
      wait();
    }

所有三个线程都会收到通知,但 synchronized 块中只能有一个线程。第一个进入块的线程添加了一个节点,所以队列又满了。其他两个线程进入块(一个接一个),但看到队列再次满,这将使它们再次进入等待状态,因为那是 loop-condition.

您可以将 wait 想象成 synchronized 块的出口和入口点。当一个线程进入wait,那么相应的锁就会被释放。一直在 wait 中等待并收到通知的线程正在尝试再次获取临界区的相应锁,如果当前正在使用则阻塞。所以通知的三个线程中一次只能有一个进入。

请注意 .enqueue() 中的 wait() 在循环内。任何被唤醒的线程都将 re-check 允许添加一个元素,并且由于一次只有一个线程可以执行同步方法,所以不会有问题 - 一个线程幸运地插入一个元素,其他线程在失败后继续等待 re-check.