notify()而不是notifyAll()阻塞队列 [英] notify() instead of notifyAll() for blocking queue

查看:206
本文介绍了notify()而不是notifyAll()阻塞队列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图找出是否可以有一个多个生产者/多个消费者队列,我可以使用 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆