簡體   English   中英

Java:殺死由ExecutorService作為Runnable啟動的線程

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM