我正在尝试找出是否可以有多个生产者/多个消费者队列,我可以在其中使用 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/