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

Joe*_*tov 9 java concurrency blockingqueue

考虑一个BlockingQueue和几个线程等待poll(long, TimeUnit)(可能还在上take()).

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

Object.notify()LinkedBlockingQueue因为线程正在等待内部锁定而无法工作.

有任何直截了当的方式吗?

unb*_*eli 13

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

BlockingQueue本质上不支持任何类型的"关闭"或"关闭"操作,以指示不再添加任何项目.这些功能的需求和使用倾向于依赖于实现.例如,一种常见的策略是生产者插入特殊的流末端或毒物对象,这些对象在被消费者采用时会相应地进行解释.

  • 好主意:作为一个大型国际机场的搬运工,我们过去常常在传送带上放一个空的白色盒子,向接收方的搬运工表明该航班不再有行李 - 白盒子就是你所说的毒. (9认同)

Pét*_*rök 5

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

这意味着InterruptedException在阻塞方法周围正确捕获和处理s,并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(); }
}
Run Code Online (Sandbox Code Playgroud)

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