![](/img/trans.png)
[英]Can you interrupt BufferedReader.readLine() with 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.