2009-12-16 118 views
13

我有一个长期运行的任务,是这样的:Java的长时间运行的任务线程中断VS取消标志

public void myCancellableTask() { 
    while (someCondition) { 
     checkIfCancelRequested(); 
     doSomeWork(); 
    } 
} 

任务可以取消(取消请求和checkIfCancelRequested()检查取消标志)。通常当我写这样的可取消循环时,我使用一个标志来指示已经请求了取消。但是,我知道我也可以使用Thread.interrupt并检查线程是否被中断。我不确定哪个是首选的方法,为什么,想法?

感谢,

杰夫

回答

6

中断将爆炸线程出指定的等待条件的列表中。你自己的取消标志不会。如果你想中断等待IO和事件,使用中断。否则使用你自己的。

0

我认为这是大多数情况下的偏好问题。 个人而言,我会去为手工制作的国旗。它给你更多的控制 - 例如,这样你可以确保你的线程不会让其他对象处于不一致的状态。 此外,如果性能非常关键,请记住使用异常会产生开销(即使它在99%的情况下可忽略不计)。

1

这取决于doSomeWork()的实现。这是纯计算还是(在任何时候)涉及阻塞API(如IO)调用?根据bmargulies的回答,JDK中的许多阻塞API都是可中断的,并会将中断的异常传播到堆栈中。

因此,如果工作需要潜在的阻塞活动,那么即使您决定使用标志控制进程,并且应该适当地捕获并处理/传播中断,您也需要考虑中断。

除此之外,如果依靠一个标志,请确保您的标志声明为volatile语义。

20

使用中断的一个问题是,如果你不控制所有的代码执行,在运行中断的风险,不能正常工作“正常”,因为别人的如何处理中断破理解在其图书馆。这是API 无形中围绕其处理依赖的interrupt导出API。

在您的例子,假设doSomeWork是第三方JAR,看起来像:

public void doSomeWork() { 
    try { 
     api.callAndWaitAnswer() ; 
    } 
    catch (InterruptedException e) { throw new AssertionError(); } 
} 

现在你要处理的AssertionError(或任何你正在使用可能会引发库)。我看到有经验的开发人员在接收中断时会抛出各种废话!另一方面,也许该方法看起来像这样:

public void doSomeWork() { 
    while (true) { 
     try { 
      return api.callAndWaitAnswer() ; 
     } 
     catch (InterruptedException e) { /* retry! */ } 
    } 
} 

这种“不正确的处理”中断会导致您的程序无限循环。再次,不要把这看成是荒谬的;那里有很多破坏的中断处理机制。

至少使用自己的国旗对任何第三方库都是完全不可见的。

+1

好东西在这里。看到吞咽中断或者只是记录并继续而不重置中断标志是很常见的。我认为人们会感到沮丧,因为这是一个经过检查的异常,他们不知道该怎么处理,所以他们根本没有做任何事情。 – 2009-12-16 21:37:02

相关问题