2010-01-21 31 views
5

我想管理我的TaskExecutor返回的期货对象列表。
我有这样的事情Java线程 - 奇怪的Thread.interrupted()和future.cancel(true)行为

List<Future<String>> list 

void process(ProcessThis processThis) {  
    for (...) { 
     Future<String> future = taskExecutor.submit(processThis); 
     list.add(future) 
    } 
} 


void removeFutures() { 
    for(Future future : list) { 
     assert future.cancel(true); 
} 

ProcessThis是,Thread.interrupted实现可赎回<字符串>并检查任务()状态

public String call() { 
     while (true) { 
      if (Thread.interrupted()) { 
       break; 
      } 
      doSomething(); 
     } 
    } 

现在的问题是,只有一个子集并发线程在调用Thread.interrupted()时返回'true'。
removeFutures()中的断言对于每个将来的删除都会返回true(我同时检查了isDone()和isCompleted()
中断的线程数是随机的超过15个正在运行的线程有时会被中断,有时候是2 ...
我真的不明白问题在哪里,如果我调用future.cancel(true)并返回true,然后检查Thread.interrupted(这只会被调用一次),我期望这回也是如此。
我失去了什么的任何想法?

我在构建Java 1.6.0_02-B05

回答

2

至少,你应该恢复INTERR uption标志做出了taskExecutor知道线程中断:

public String call() { 
    while (true) { 
     if (Thread.interrupted()) { 
      Thread.currentThread().interrupt(); 
      break; 
     } 
     doSomething(); 
    } 
} 
+0

感谢您的回复。这样做有什么意义?如果Thread.interrupted()返回true我打破了while循环,我基本上杀死了线程。问题是,即使相关的future.cancel(true)返回true,有时Thread.interrupted()也会返回'false'。您编辑的行当时甚至无法达到。 – marts

+0

然后中断标志可能在'doSomething()'的某个地方丢失(出于同样的原因 - 重置标志并且不恢复)。也就是说,我的回答中的示例是一个基本原则,应该用来避免丢失中断 – axtavt

+0

如果是这种情况('避免丢失中断'),我不能只使用像Thread.currentThread()。isInterrupted()而不是每次使用Thread.interrupted()都必须恢复中断状态。 (顺便说一句,这是一个错误:http://stackoverflow.com/questions/2012259/)我没有处理doSomething中的中断状态。 – marts

2

中断处于经常吞食的潜在问题。因此,在doSomething()深处(甚至在类加载中),中断可能会被wait()所捕获,然后被“粗心”代码丢弃。中断是邪恶的,国际海事组织。

这可能是值得检查的,你们所有的任务实际上是在取消时运行。

6

请注意,Thread.interrupted()返回当前中断状态,然后清除,因此所有将来的调用都将返回false。你想要的可能是Thread.currentThread().isInterrupted()

另请注意,如果任务已完成或取消,future.cancel(true)通常只会返回false。如果它返回true,那么不能保证该任务将被实际取消。

doSomething()中发生了什么?由于中断,RuntimeException可能会在某处出现。你有一套UncaughtExceptionHandler套装吗?如果不是,则需要将ThreadFactory传递给Executor,它将设置异常处理程序并记录任何遗漏的异常。

+0

我知道这一点。我在while {)之后只调用一次Thread.interrupted()。无论如何,如果它返回真实我打破;并立即杀死线程(并且我没有触及/检查其他地方的中断)。我会看看UncaughtExceptionHandler。非常感谢您的回复。 ()注意Thread.currentThread()中的这个错误isInterrupted()http://bugs.sun.com/view_bug.do?bug_id=6772683) – marts

+0

目前,您正确使用Thread.interrupted()安全的方式。但是,如果您不需要该方法提供的行为,则不应该将其用作其他人(或您自己)重构该方法,以便以中断处理无效的方式调用Thread.interrupted() 。如果可以的话,使用Thread.currentThread()。isInterrupted()更安全。 – Kevin

+0

嗨凯文。你是对的,但由于java许可证问题,我无法更新当前的JVM 1.6.0_02-b05。我在多处理器机器上运行,我的JVM可能会受到我在之前评论中链接的错误的影响(这里是一个在stackoverflow http://stackoverflow.com/questions/2012259/中的相关帖子)。关于未处理的异常,如果一个RuntimeException转义,我可以让这个线程自己死掉,对吗?这里我的问题是相反的..他们不停止。 (或至少它们的一个子集被停止) – marts