如何立即释放在BlockingQueue上等待的线程

时间:2010-07-22 07:56:36

标签: java concurrency blockingqueue

考虑BlockingQueue以及等待poll(long, TimeUnit)的几个主题(也可能在take()上)。

现在队列为空,希望通知等待的线程他们可以停止等待。预期的行为是返回null或抛出声明的InterruptedException

由于线程正在等待内部锁定,

Object.notify()将不适用于LinkedBlockingQueue

任何直截了当的方式?

3 个答案:

答案 0 :(得分:13)

BlockingQueue的Javadoc提出了一个好方法:

  

BlockingQueue本质上不是   支持任何一种“关闭”或   “关闭”操作表明   不会再添加任何项目。需求   并且这些特征的使用倾向于   实现有关。 例如,   一个共同的策略是生产者   插入特殊的流末尾或毒药   对象,被解释   因此,当消费者采取时。

答案 1 :(得分:5)

传统的方法是中断线程,但这当然要求它们正确处理中断。

这意味着要在阻塞方法中正确捕获和处理InterruptedException,并定期检查(并采取行动)interrupted标志。

  

API或语言规范中没有任何内容将中断与任何特定的取消语义联系起来,但在实践中,除了取消之外,使用中断是非常脆弱的,并且难以在较大的应用程序中维持。 [...]

     

中断通常是实施取消的最明智方式。

在第7.1.1节中说Java Concurrency in Practice。正确处理中断的一个例子(这是生产者线程,而不是消费者,但在当前上下文中这种差异可以忽略不计):

class PrimeProducer extends Thread {
    private final BlockingQueue<BigInteger> queue;

    PrimeProducer(BlockingQueue<BigInteger> queue) {
        this.queue = queue;
    }

    public void run() {
        try {
            BigInteger p = BigInteger.ONE;
            while (!Thread.currentThread().isInterrupted())
                queue.put(p = p.nextProbablePrime());
        } catch (InterruptedException consumed) {
            /*  Allow thread to exit  */
        }
    }
    public void cancel() { interrupt(); }
}

另一种解决方案是将poll的超时参数设置得相当低,以便线程定期唤醒并且可以足够快地注意到中断。我仍然认为根据您的特定线程取消策略明确处理InterruptedException始终是一个好习惯。

答案 2 :(得分:1)

我说你的设计有问题。消耗掉BlockingQueue的线程不应该以这种方式中断。如果他们必须定期执行其他操作(例如检查变量的状态),同时也从队列中消耗,那么您应该使用poll()方法,并相应地设置超时,以便两个操作可以交错。 / p>