2010-01-21 60 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