是什么会导致executorService.invokeAll()抛出中断的exception



javadoc说 invokeAll(Collection<> callables)

interruptedException-如果在等待时中断,在这种情况下,未完成的任务被取消

但是没有关于为什么会中断呼叫的文档。我的程序这样做 - 但很少,我无法编写会导致它发生的测试。

我使用的是一个参数方法而无需超时。

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!
        }
    }
}

intruptedException是从 java.util.concurrent.FutureTask.awaitDone(FutureTask.java:40‌​0)

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

可以同时运行的许多ParallelUtils(从不同的线程启动),但是如您所见,每个呼叫都会创建自己的ExecutorService,因此它们不应该彼此搞砸。

(作为附带问题,我可以在所有呼叫的情况下使用共享池,而无需互相混乱吗?)

可以同时运行许多此类平行行动(从不同的线程启动)

显然,这些线程中的至少一个直接通过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
   }    
}

什么会导致ExecutorService.invokeAll()投掷InterruptedException

请参阅shutdownNow()的Javadoc:

除了最好的努力试图停止处理主动执行任务之外,没有任何保证。例如,典型的实现将通过Thread.interrupt()取消,因此任何未能响应中断的任务都可能永远不会终止。

由于invokeAll等待直到完成的所有任务,从另一个线程调用shutdownNow()invokeAll调用可以中断的一种方式。


但是,在代码中,您已经向我们显示了它,没有呼叫shutdownNow(),也没有明显的方法让executor Service对象泄漏到另一个线程。

您的代码(或其他库代码)中的某些内容也可能调用Thread.interrupt。例如,其中一个任务可能是对自己做。

最新更新