阻止队列设计

时间:2012-05-15 10:09:56

标签: java design-patterns queue

n个线程生成BlockingQueue。 当队列已满时,消费者会排空队列并进行一些处理。

我应该如何决定以下两种实施方式?

选择A: 消费者定期轮询队列以检查它是否已满,所有作者都在等待(毕竟它是一个阻塞队列:)。

选择B: 我使用同步“put”方法实现自己的队列。在放置提供的元素之前,我测试队列是否几乎已满(完全减去1个元素)。然后我放置元素并通知我的消费者(正在等待)。

第一个解决方案是最简单的但是进行轮询;这让我烦恼 在我看来,第二种解决方案更容易出错,更需要更多编码。

5 个答案:

答案 0 :(得分:2)

我建议编写一个代理队列,它将内部包装一个队列实例和一个Exchanger实例。您的代理方法将调用委托给您的内部队列。添加时检查内部队列是否已满,当它已满时,将内部队列与使用者线程交换。消费者线程将交换空队列以换取填充的队列。您的代理队列将继续填充空队列,而使用者可以继续处理已填充的队列。这两个活动可以并行运行。当双方都做好准备时,他们可以再次交换。

class MyQueue implements BlockingQueue{
    Queue internalQueue = ...
    Exchanger<Queue> exchanger;

    MyQueue(Exchanger<BlockingQueue> ex){
    this.exchanger = ex;
    }

     .
     .
     .

    boolean add (E e) {
      try{
        internalQueue.add(e);
      }catch(IllegalStateException ise){
        internalQueue = exchanger.exchange(internalQueue);
      }
      internalQueue.add(e);     
    }

}

class Consumer implements Runnable {
    public void run() {
        Queue currentQueue = new empty queue;
        while (...){
           Object o = currentQueue.remove();
           if (o == null){
              currentQueue = exchanger.exchange(currentQueue);
              continue;
           }
           //cast and process the element
        } 
    }
}

答案 1 :(得分:0)

第二种解决方案显然更好。它并没有那么复杂。您可以继承或包装任何其他BlockingQueue并覆盖其方法offer(),如下所示:调用“real”offer()。如果它返回true,请退出。否则触发工作线程工作,并立即调用offer()超时。

这是几乎伪代码:

public boolean offer(E e) {
    if (queue.offer(e)) {
        return true;
    }
    boolean result = queue.offer(e, timeout, unit); // e.g. 20 sec. - enough for worker to dequeue at least one task from the queue, so the place will be available.
    worker.doYouJob();
    return result; }

答案 2 :(得分:0)

我不知道你需要这样的队列实现:消费者在队列变满时等待,只有当它完全耗尽并开始处理时。

您的队列应该被阻止,直到消费者满员为止。认为您需要覆盖drain()方法以使其在队列变满时等待。比你的消费者只是打电话等待排水方法。不需要从生产者到消费者的通知。

答案 3 :(得分:0)

使用观察者模式。让您的消费者注册队列通知程序。当生产者放置队列然后决定是否通知任何听众。

答案 4 :(得分:0)

我使用了CountdownLatch,这很简单,效果很好。 感谢其他想法:)