java - 用于阻塞队列的 notify() 而不是 notifyAll()

标签 java multithreading data-structures queue blockingqueue

我正在尝试找出是否可以有多个生产者/多个消费者队列,我可以在其中使用 notify() 而不是 notifyAll()。例如,在下面的实现中(来源:here),您不能简单地将 notifyAll() 切换为 notify()。不能切换的原因并不十分明显,所以我将把它作为一个预告片留给任何想帮助我理解这个问题的人。

所以下面的代码是错误的:

public class BlockingQueue {

  private Object lock = new Object();

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

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


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


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

    return this.queue.remove(0);
  }
 }
}

最佳答案

以下步骤导致我们陷入僵局。让我们将 limit 设置为 1 以保持示例简洁。

  • E1 排队一个项目。
  • E2 尝试入队 - 检查等待循环 - 已经满 - 等待
  • E3 尝试入队 - 检查等待循环 - 已经满 - 等待

  • D1 尝试出列 - 并且正在执行同步块(synchronized block)

  • D2 尝试出列 - block 进入(同步) block - 由于 D1
  • D3 尝试出队 - 在进入(同步) block 时阻塞 - 由于 D1

  • D1 正在执行 enqueue - 获取项目,调用通知,退出方法

  • 通知碰巧唤醒了 E2(即“任何等待线程”)
  • 但是,D2 在 E2 之前进入同步块(synchronized block)(E2 必须重新获取锁),因此 E2 在进入排队同步块(synchronized block)时阻塞
  • D2 检查等待循环,队列中没有更多项目,所以等待
  • D3 在 D2 之后,但在 E2 之前进入 block ,检查等待循环,队列中没有更多项目,因此等待

  • 现在有 E3、D2 和 D3 等待!

  • 最终E2获取锁,入队,调用notify,退出方法

  • E2 的通知唤醒 E3(记住任何线程都可以被唤醒)

  • E3 检查等待循环条件,队列中已经有一个项目,所以等待。
  • 没有更多的线程可以调用 NOTIFY 并且三个线程被永久挂起!

解决方案:用 notifyAll 替换 notify

关于java - 用于阻塞队列的 notify() 而不是 notifyAll(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13774802/

相关文章:

java - Spring 安全4 : Access denied for admin role

ios - 一段时间后 dispatch_queue_t 变慢

multithreading - iOS 上的 GCD 可以处理数百个已调度的 block 吗?

c# - 任务完成时运行函数

c - 初始化 Valgrind 错误

java - 如何将鼠标监听器添加到包含呈现为复选框的 boolean 值的 JTable 单元格

java - 不止一个可变参数参数

java - 如何使jar文件在启动时运行

c++ - 在不使用临时变量进行交换时,swap(int&, int&) 函数不起作用?

algorithm - spoj 上 LIS2 的方法