[英]Java: Killing a thread launched as a Runnable by ExecutorService
我有一個系統,當它接到來自Web服務的呼叫時啟動工作人員。 工作程序由ExecutorService啟動,正在啟動的類實現Runnable。 但是,如果工作人員超時,我實際上無法殺死工作人員,這會導致我的系統出現資源問題。
public class MyClass implements Runnable {
public void internalCall() {
logger.info("B-1");
//Some business code which may take too long
// <...>
logger.info("B-2");
}
public void launch() {
// Wrapper
Callable<Object> callable = new Callable<Object>() {
@Override
public Object call() throws Exception {
internalCall();
return null;
}
};
// Submit
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Object> future = executor.submit(callable);
try {
// Wait
future.get(1, TimeUnit.SECONDS);
}
catch (TimeoutException e) {
logger.warn("Timeout");
}
finally {
logger.info("A-1");
executor.shutdownNow();
future.cancel(true);
logger.info("A-2");
}
}
}
如果工作人員超時,我希望以下日志消息:
INFO | B-1
WARN | Timeout
INFO | A-1
INFO | A-2
隨后服務保持空閑狀態,直到另一個工作者請求進入。但是,盡管在ExecutorService和Future上調用了shutdownNow()和cancel(),但工作人員繼續:
INFO | B-1
WARN | Timeout
INFO | A-1
INFO | A-2
INFO | B-2
我環顧四周,還有一些關於殺死線程的類似問題,一般的共識是你不應該這樣做。 但是,這是一個可以擴展的類,意圖覆蓋internalCall() - 這意味着我不能依賴internalCall來監視自己並檢查Thread.isInterrupted()或類似的東西。
我想通過攻擊furure或executor對象來強制從launch()方法中刪除東西。
NB
如果一個線程沒有響應Thread.interrupt怎么辦?
在某些情況下,您可以使用特定於應用程序的技巧。 例如,如果線程正在等待已知套接字,則可以關閉套接字以使線程立即返回。 不幸的是,確實沒有任何技術可以發揮作用。 應該注意的是,在等待線程沒有響應Thread.interrupt的所有情況下,它也不會響應Thread.stop。 此類情況包括故意拒絕服務攻擊,以及thread.stop和thread.interrupt無法正常工作的I / O操作。 - Java Thread Primitive Deprecation
那么我們學到了什么......在Java中,不要運行第三方代碼,而這些代碼在主應用程序的同一執行中實際上是不可信任的。 即使Thread.stop確實工作,你仍然有很多其他東西比沒有檢查中斷狀態的線程(即代碼調用System.exit(0)
)更糟糕。
我建議你做的第三方代碼是你不能相信的:
將第三方代碼作為由Java運行的控制執行的計算語言運行。 一些例子是:規則語言,如Drools或無邏輯模板語言,如JMustache。
在單獨的執行中運行第三方代碼,並使用您的操作系統終止進程和IPC,例如用於通信的套接字。
首先, future.cancel(true)
不會殺死正在運行的線程。 它只是試圖以“禮貌的方式”停止執行。
它的作用是或多或少地發送中斷信號,就像在代碼中某處調用yourthread.interrupt()
。
僅當run()方法中的代碼檢查中斷時,它才會停止處理。 因此,在internalCall()
您需要立即檢查線程是否通過調用Thread.interrupted()
而中斷,並停止執行。 中斷還會通過拋出InterruptedExcepiton來停止sleep(),wait(),IO操作(這就是為什么那些方法拋出這樣的異常)。
ExecutorService
使用相同的機制,因此它將嘗試中斷正在運行的線程,但是,如果您的代碼沒有檢查此類中斷,則線程將繼續運行。
由於各種原因,不應該簡單地殺死線程(檢查java doc for thread.stop()方法以及為什么不推薦使用它),並且通知線程可能它們應該停止工作的“通用”方式是中斷信號。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.