如何使用关键原子逻辑安全地中断线程?

时间:2013-01-03 19:29:01

标签: java multithreading synchronization

我有一个在循环中执行两个操作的线程:等待来自BlockingQueue的对象然后处理它们。处理逻辑具有可在JVM外部观察到的效果,必须以原子方式完成。

目前,这个线程由一个易变的布尔变量控制,如https://stackoverflow.com/a/10961760/499922中所述。但是,这意味着如果队列中没有更多消息要消耗,则线程将不会停止。 'Thread.interrupt()`不能用来解决这个问题,因为它可以在一半时间中断原子操作。

有没有办法只是中断队列中的take()方法而不是其他任何操作?

4 个答案:

答案 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()