簡體   English   中英

Future.cancel(true)不能可靠地取消/中斷線程

[英]Future.cancel(true) does not reliably cancel/interrupt thread

我嘗試與CompletionService並行執行幾個任務。 當我嘗試執行取消時,就會出現問題。

這是我使用的代碼的草圖:

void startTasks(int numberOfTasks) throws Exception {

    ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads);
    CompletionService<TaskResultType> completionService = new ExecutorCompletionService<TaskResultType>(executor);
    ConcurrentLinkedQueue<TaskResultType> results = new ConcurrentLinkedQueue<BenchmarkResult>();
    ArrayList<Future> futures = new ArrayList<Future>();

    for (int i = 0; i < numberOfTasks ; i++) {
        TypeOfTask task = ... ; 
        Future future = completionService.submit(task);
        futures.add(future);
    }

    boolean failed = false;
    Throwable cause = null;
    for (int i = 0; i < numberOfThreads; i++) {
        try {
            Future<TaskResultType> resultFuture = completionService.take();
            TaskResultType result = resultFuture.get();
            results.add(result);
        } catch (ExecutionException e) {
            failed = true;
            cause = e.getCause();
            /* cancel all other running tasks in case of failure in one task */
            for (Future future : futures) {
                future.cancel(true);
            }
        } catch (CancellationException e) {
            // consume (planned cancellation from calling future.cancel())
        }

    }
    executor.shutdown();
    // code to throw an exception using cause
}

任務實現Callable

現在,在大多數情況下,當我在其中一個任務中拋出異常時,它可以正常工作,即,我立即從其他任務中獲得CancellationExceptions,並且任務立即完成(將這種情況稱為A)。 但有時(讓我們將這種情況稱為B),某些任務首先完成,然后引發CancellationException。 對於所有任務,Future.cancel(true)在兩種情況下均返回true(具有初始ExecutionException的任務除外,因為該任務已被取消)。

我使用Thread.currentThread.isInterrupted()檢查中斷標志,在完成的任務中(即取消失敗的任務),將中斷標志設置為false。

在我看來,所有這些似乎都是非常奇怪的行為。 有人知道問題可能是什么嗎?

更新資料

到目前為止,我最好的想法是,在包含任務的代碼中的某個深處(只有一些高級代碼來自我自己),中斷狀態被消耗了,例如被捕獲的InterruptedException所占用,該異常未將Thread.interrupt()調用為重新建立狀態。 由於線程的調度,Future.cancel()設置中斷標志的確切時間可能會略有不同,這可以解釋不一致的行為。 消耗中斷狀態會解釋情況B的行為嗎?

但有時,某些任務會先完成,然后引發CancellationException。 對於所有任務,Future.cancel(true)在兩種情況下均返回true(具有初始ExecutionException的任務除外,因為該任務已被取消)。

如果您的程序未完成(或者引發異常后需要很長時間才能完成),那么我懷疑您的問題是任務之一正在做IO或以其他方式被阻塞,並且沒有檢查Thread.currentThread().isInterrupted() 因此,即使您取消了Future並且線程被中斷,也不會被檢測到。

但是,程序似乎正在完成。 所以我不確定這里是什么錯誤情況。 如果捕獲到異常,請在列表中的所有期貨上調用future.cancel(true) 投擲的物件和已經完成的物件均應返回false因為它們無法取消。 從cancel返回true的那些應該已經被中斷。

例如。 如果倒數第二個線程引發異常,則future.cancel(true)應該僅對最后一個正在運行的線程返回true

要做的一件事是在期貨到期時將其刪除,這樣您就不必重新取消已完成的工作。 但是可能要做的就是掩蓋您現在所看到的問題:

Future<TaskResultType> resultFuture = completionService.take();
futures.remove(resultFuture);

更新:

某些代碼很可能吞下該中斷。 不幸的是,它一直在發生。 如果某些線程在取消時並沒有立即完成並正在運行以完成,則可能是這種情況。

但有時,某些任務會先完成,然后引發CancellationException。

可能是您取消了一個任務,該任務通常被中斷了(在這種狀態下,您可能認為它返回了一個結果,但是對於CompletionService,它被取消了),future是由take()返回的,您調用future.get() ,還有CancellationException

您還可以查看Guava的Futures.allAsList ,它似乎在做類似的事情:

創建一個新的ListenableFuture,其值是一個列表,其中包含所有輸入期貨的值(如果全部成功)。 如果任何輸入失敗,則返回的future失敗。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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