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

考虑一个BlockingQueue和几个等待poll(long, TimeUnit)线程poll(long, TimeUnit) (也可能在on take() )。

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

由于线程正在等待内部锁, Object.notify()将无法用于Object.notify()

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

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

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

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

这意味着在阻塞方法周围正确捕获和处理InterruptedException ,并定期检查(并处理) interrupted标志。

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

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

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

 class PrimeProducer extends Thread { private final BlockingQueue queue; PrimeProducer(BlockingQueue 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始终是一个好习惯。

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