是什么导致ExecutorService.invokeAll()抛出InterruptedException?

时间:2017-08-30 09:37:50

标签: java concurrency executorservice

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:40‌​0)

抛出InterruptedException(至少在某些情况下)

可能有许多ParallelUtils同时运行(从不同的线程启动),但正如您所看到的,每个调用都会创建自己的ExecutorService,因此它们不应该互相混乱。

(作为一个附带问题,我可以在没有invokeAll调用互相混乱的情况下为所有调用使用共享池吗?)

2 个答案:

答案 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
   }    
}