javadoc说invokeAll(Collection<> callables)
抛出
InterruptedException - 如果在等待时被中断,则在这种情况下取消未完成的任务
但没有关于呼叫可能被中断的原因的文档。我的程序是这样做的 - 但很少,我不能写一个会导致它发生的测试。
我正在使用one参数方法而没有超时。
public class ParallelUtil<T> {
public interface Task<T> {
public void execute(T data) throws Exception;
}
public void execute(final Task<T> task, Collection<T> targets) {
ExecutorService executor = null;
try {
executor = Executors.newFixedThreadPool(20);
execute(task, targets, executor);
} finally {
if (executor != null) {
try {
executor.shutdown();
} catch (Exception e) {}
}
}
}
private void execute(final Task<T> task, Collection<T> targets, ExecutorService executor) {
List<Callable<Void>> tasks = new ArrayList<>();
...
try {
executor.invokeAll(tasks);
} catch (Exception e) {
// Here we get InterruptedException - for no reason?
// With some of the tasks left undone!
}
}
}
从java.util.concurrent.FutureTask.awaitDone(FutureTask.java:400)
可能有许多ParallelUtils
同时运行(从不同的线程启动),但正如您所看到的,每个调用都会创建自己的ExecutorService
,因此它们不应该互相混乱。
(作为一个附带问题,我可以在没有invokeAll调用互相混乱的情况下为所有调用使用共享池吗?)
答案 0 :(得分:2)
什么可能导致
ExecutorService.invokeAll()
抛出InterruptedException
?
请参阅shutdownNow()
的javadoc:
除了尽力尝试停止处理主动执行任务之外,没有任何保证。 例如,典型的实现将通过
Thread.interrupt()
取消,因此任何未能响应中断的任务都可能永远不会终止。
由于invokeAll
等待完成所有任务,因此从另一个线程调用shutdownNow()
是invokeAll
调用可能被中断的一种方式。
但是,在您向我们展示的代码 中,没有对shutdownNow()
的调用,也没有明显的方法让执行程序服务对象泄漏到另一个线程。
您的代码(或其他一些库代码)中的某些内容也可能正在调用Thread.interrupt
。例如,其中一个任务可能是自己这样做。
答案 1 :(得分:2)
可以有许多这些ParallelUtils同时运行(从不同的线程启动)
显然,这些线程中的至少一个可以通过Thread.interrupt()
直接中断,也可以通过例如间接中断。 Future.cancel(true)
或ExecutorService.shutdownNow()
。
重现此中断的示例:
class Sleep implements ParallelUtil.Task<Integer> {
@Override
public void execute(Integer data) throws Exception {
Thread.sleep(Long.MAX_VALUE);
}
}
class InterruptInvokeAll {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(1);
executorService.submit(
() -> {
ParallelUtil<Integer> parallelUtil = new ParallelUtil<>();
parallelUtil.execute(new Sleep(), Arrays.asList(1));
});
executorService.shutdownNow(); // indirectly interrupts thread that calls executor.invokeAll
}
}