2017-09-13 97 views
1

問題invokeAll是超時中斷

如何做出一系列已經與invokeAll停止執行超時線程。

背景

我有callables我想等完成的列表。但是,如果他們沒有在規定時間內完成(比如說一秒),我想取消它們。這似乎很容易與

executor.invokeAll(callables, 1000l, TimeUnit.MILLISECONDS); 

所以一秒鐘後,它會超時很好,我可以繼續我的一天。但是在後臺,線程仍然處於活動狀態,可能會執行一些代碼段。本質上他們不會中斷,我不想發生 - 我希望線程停止執行。

有沒有什麼方法可以在invokeAll超時後使用返回的期貨清單來停止線程?

+0

該文檔說,返回的任務未完成時將被取消。 http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html#invokeAll%28java.util.Collection,%20long,%20java.util.concurrent.TimeUnit%29 – pshirishreddy

+0

我認爲他們被取消了,但他們仍然活着,甚至在'invokeAll'已經停止阻止後可以繼續記錄。 – Deepak

+0

線程在做什麼?有線程沒有響應中斷的各種可能的原因(阻塞IO,代碼吃掉中斷,代碼忽略中斷,等待進入同步塊...) – bowmore

回答

1

你不能有方式。

ExecutorService「框架」允許您僅考慮Callable對象和Future結果。這個抽象隱藏了涉及的所有線程的低級細節。因此:即使這是可能的,你的想法很可能是一個「骯髒的黑客」。換句話說:如果你想低級別的,直接訪問線程做某事 - 那麼你可能必須使用自己的「線程池」實現。

中間層:請記住這些線程執行您的 Callable/Runnable實例。你當然可以想到這些對象定期檢查某種「命令隊列」。當隊列包含取消請求 - 然後您的 Callable中的代碼停止執行其工作。

+0

你的評論是有道理的,但我真的不會避風港當我給'invokeAll'超時時,我認爲這將是標準行爲。很奇怪的是,保持運行的線程是「有效停止」的,但在調用引發'InterruptedException'的事件之前不會中斷。對於被中斷的異常,應該有更高級別的輪詢方式 – Deepak

+0

問題是:「中斷」線程並不是你在Java中「常用」的做法。當你長時間運行Runnable/Callable代碼時,那麼你有該代碼以某種方式檢查一些「取消」標誌。 – GhostCat

1

ExecutorService被設計爲支持,以應對interruption.任務cancellation因此,要做到這一點,正確的方法是使你的Callable實現注意到他們已經中斷。

如果您的任務純粹是計算上的,或者它經常循環,調用第三方庫,這很容易。某處在你的任務,你將有一個循環,看起來像:

while (!Thread.interrupted()) { 
    /* Keep going */ 
} 

當然,你可能在你的循環測試等特定任務的條件太多,但你應該是測試電流的斷續狀態線。

調用interrupted()將清除中斷狀態。調用Thread.currentThread().isInterrupted()將保持中斷狀態。對於ExecutorService中的工作線程,保持中斷狀態無關緊要—服務正在中斷它自己的線程,並且當線程從您的任務返回時,服務將清除狀態而不查看它。但是,這是一個很好的習慣,所以如果你的代碼被合併到一個任務中,它將會很好地工作。在獲取InterruptedException或使用Thread.interrupted()檢測後重新斷言中斷狀態,只需致電Thread.currentThread().interrupt()即可。

如果任務是對不支持中斷的第三方庫的長期調用,或者阻止對不間斷I/O操作的調用,那麼您的「任務」要困難得多。你可能完全沒有運氣,或者你可能會發現一個混亂異步中止操作。

例如,如果您創建Socket,並將它(或其流)傳遞給您的任務,則可以異步關閉套接字。如果invokeAll超時,調用者將需要額外的代碼來關閉套接字。

相關問題