我有一个在循环中执行两个操作的线程:等待来自BlockingQueue的对象然后处理它们。处理逻辑具有可在JVM外部观察到的效果,必须以原子方式完成。
目前,这个线程由一个易变的布尔变量控制,如https://stackoverflow.com/a/10961760/499922中所述。但是,这意味着如果队列中没有更多消息要消耗,则线程将不会停止。 'Thread.interrupt()`不能用来解决这个问题,因为它可以在一半时间中断原子操作。
有没有办法只是中断队列中的take()
方法而不是其他任何操作?
答案 0 :(得分:2)
' Thread.interrupt()`不能用于解决这个问题,因为它可以在一半时间中断原子操作。
它没有做到这一点。它所做的就是设置一个与设置volatile字段非常相同的标志。
即使您使用已被弃用的Thread.stop()
并且可以触发任何代码行来引发错误,您仍然可以捕获此类错误并确保您的数据处于一致状态。
我不会创建一个队列和线程来执行此队列中的任务,而是使用具有这两者的ExecutorService,它可用于取消/中断单个任务,支持多个线程,正常关闭或立即关闭等待终止。
你很可能最好不要重新发明这个轮子。 ;)
答案 1 :(得分:1)
执行此操作的一种方法是将特殊的“sentinel”对象放入队列中。线程将知道此特殊对象的含义,并在收到它时采取适当的操作。
答案 2 :(得分:1)
我发现在这种情况下最好的方法是使用“毒丸” - 你在队列中放置一个对象,该对象仅用于切换某个动作。
在实践中广泛涉及Java并发(我的副本中的第155页,7.2.3)。有关该部分的程序化示例,请参阅here。
答案 3 :(得分:0)
不依赖于volatile布尔值,而是依赖线程的中断标志:
while (!Thread.currentThread().isInterrupted()) {
try {
Object value = queue.take();
handle(value);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
这样当流程在take()
上被阻塞时,它将在线程中断时立即退出循环。如果它在任何其他时间中断,它将在完成当前循环后退出循环。
或者你可以编码它以在中断后继续循环,只要队列中的对象立即可用,然后使用poll()
。