考虑BlockingQueue
以及等待poll(long, TimeUnit)
的几个主题(也可能在take()
上)。
现在队列为空,希望通知等待的线程他们可以停止等待。预期的行为是返回null
或抛出声明的InterruptedException
。
Object.notify()
将不适用于LinkedBlockingQueue
。
任何直截了当的方式?
答案 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>