notify()而不是notifyAll()阻塞队列 [英] notify() instead of notifyAll() for blocking queue
问题描述
notify()
而不是 notifyAll()
。例如,在下面的实现中(来源: here ),你不能只是只需在 notify()
中切换 notifyAll()
。这不是很明显,为什么你不能切换,所以我会把它作为一个传情给任何想要帮助我理解这个问题的人。 所以下面的代码是坏的:
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);
}
}
}
以下步骤导致我们陷入僵局。我们将限制设置为1 以保持示例简洁。
- E1将一个项目排队。
- E2尝试排队 - 检查等待循环 - 已经满 - 等待
-
E3尝试排队 - 检查等待循环 - 已经满 - 等待
>
-
D1尝试出队 - 正在执行同步块
- D2尝试出队 - 进入(同步)块的块 - 由于D1
-
D3尝试出队 - 进入(同步)块的块 - 由于D1
-
D1正在执行排队 - 获取项目,调用notify,exit方法
- 通知正在唤醒E2(即任何等待线程) 但是,在E2可以(E2必须重新获取锁定)之前,D2进入同步块,因此进入入队同步块时的E2块
- D2检查等待循环,不再有队列中的项目,所以等待
-
D3在D2之后进入块,但在E2之前,检查等待循环,不再有项目在队列中,所以等待
-
现在有E3,D2和D3等待!
- p>最后E2获取锁,排队一个项目,调用notify,exit方法
-
E2的通知唤醒E3(记住任何线程都可以被唤醒) >
- E3检查等待循环条件,队列中已经有一个项目,所以等待。
- 没有更多的线程呼叫通知和三线程永久暂停!
解决方案:使用notifyAll替换通知
I am trying to find out whether it is possible to have a multiple producer / multiple consumer queue where I can use notify()
instead of notifyAll()
. For example, in the implementation below (source: here) you cannot just simply switch the notifyAll()
for notify()
. It is not totally obvious why you cannot switch so I will leave it as an teaser to whoever wants to help me out understanding this problem.
So the code below is broken:
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);
}
}
}
The following steps lead us to deadlock. Let's set limit to 1 to keep the example brief.
- E1 enqueues an item.
- E2 attempts enqueue - checks wait loop - already full - waits
E3 attempts enqueue - checks wait loop - already full - waits
D1 attempts dequeue - and is executing synchronized block
- D2 attempts dequeue - blocks on entry to the (synchronized) block - due to D1
D3 attempts dequeue - blocks on entry to the (synchronized) block - due to D1
D1 is executing enqueue - gets the item, calls notify, exits method
- The notify happens to wake up E2 (i.e. "any waiting thread")
- BUT, D2 enters sync block before E2 can (E2 must reacquire the lock), so E2 blocks on entry to the enqueue sync block
- D2 checks wait loop, no more items in queue, so waits
D3 enters block after D2, but before E2, checks wait loop, no more items in queue, so waits
Now there is E3, D2, and D3 waiting!
Finally E2 acquires the lock, enqueues an item, calls notify, exits method
E2's notification wakes E3 (remember any thread can be woken)
- E3 checks the wait loop condition, there is already an item in the queue, so waits.
- NO MORE THREADS TO CALL NOTIFY and THREE THREADS PERMANENTLY SUSPENDED!
SOLUTION: Replace notify with notifyAll
这篇关于notify()而不是notifyAll()阻塞队列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!