![](/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.