我试图找出是否可以使用多个生产者/多个消费者队列,我可以使用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);
}
}
}
答案 0 :(得分:10)
以下步骤导致我们陷入僵局。我们将限制为1 以保持示例简短。
E3尝试入队 - 检查等待循环 - 已满 - 等待
D1尝试出列 - 并且正在执行synchronized块
D3尝试出列 - 阻止进入(同步)块 - 由于D1
D1正在执行enqueue - 获取项目,调用notify,退出方法
D3在D2之后进入阻止,但在E2之前,检查等待循环,队列中没有其他项目,所以等待
现在有E3,D2和D3在等待!
最后E2获取锁定,排队项目,调用通知,退出方法
E2的通知唤醒E3(记住任何线程都可以被唤醒)
解决方案:将notify替换为notifyAll
答案 1 :(得分:0)
无论您的设计是什么,都知道notify()
唤醒当前正在等待锁对象的随机线程,notifyAll()
唤醒所有这样的线程(以随机顺序)。
只要你的等待线程被编码为处理你给它们的唤醒类型,就没有问题了。
一个并不比另一个好:在某些情况下notify()
是最佳选择,在其他情况notifyAll()
中 - 它取决于正在处理的问题。
答案 2 :(得分:0)
将notify
移出两种方法中的条件语句(不再需要这些条件),一切都应该正常工作。
并且,在原始源中,方法是同步的。你为什么把它改为synchronized(lock)
?只是忘记将wait
更改为lock.wait()
?