考虑一个BlockingQueue
和几个线程等待poll(long, TimeUnit)
(可能也在 on take()
)。
现在队列是空的,需要通知等待的线程他们可以停止等待。预期的行为是null
返回或声明的InterruptedException
抛出。
Object.notify()
LinkedBlockingQueue
由于线程正在等待内部锁,因此无法正常工作。
有什么直截了当的方法吗?
考虑一个BlockingQueue
和几个线程等待poll(long, TimeUnit)
(可能也在 on take()
)。
现在队列是空的,需要通知等待的线程他们可以停止等待。预期的行为是null
返回或声明的InterruptedException
抛出。
Object.notify()
LinkedBlockingQueue
由于线程正在等待内部锁,因此无法正常工作。
有什么直截了当的方法吗?
BlockingQueue 的 Javadoc 提出了一个好方法:
BlockingQueue 本质上不支持任何类型的“关闭”或“关闭”操作来指示不再添加项目。此类功能的需求和使用往往取决于实现。例如,一种常见的策略是生产者插入特殊的流尾或有毒对象,当消费者采用时会相应地解释这些对象。
常规的方法是中断线程,但这当然需要它们正确处理中断。
这意味着要围绕阻塞方法正确捕获和处理InterruptedException
s,否则要定期检查(并采取行动)interrupted
标志。
API 或语言规范中没有任何内容将中断与任何特定的取消语义联系起来,但在实践中,将中断用于除取消之外的任何事情都是脆弱的,并且难以在大型应用程序中维持。[...]
中断通常是实现取消的最明智的方式。
在第 7.1.1 节中说Java 并发实践。一个正确处理中断的示例,来自相同的(这是一个生产者线程,而不是消费者,但在当前上下文中这种差异可以忽略不计):
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 始终是一种好习惯。
我会说你的设计有问题。消耗 BlockingQueue 的线程不需要以这种方式中断。如果他们必须定期执行其他操作(例如检查变量的状态),同时还要从队列中消费,那么您应该使用 poll() 方法并相应地设置超时,以便两个操作可以交错。