Esko Piirainen
Esko Piirainen

Reputation: 1379

What can cause ExecutorService.invokeAll() to throw an InterruptedException?

The javadoc says invokeAll(Collection<> callables) throws

InterruptedException - if interrupted while waiting, in which case unfinished tasks are cancelled

but there is no documentation on why the call could be interrupted. My program does so - but very rarely and I can not write a test that would cause it to happen.

I'm using the one parameter method without a timeout.

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

InterruptedException is thrown (at least in some cases) from java.util.concurrent.FutureTask.awaitDone(FutureTask.java:40‌​0)

There can be many of these ParallelUtils running at the same time (launched from different threads), but as you can see each call creates its own ExecutorService, so they should not mess each other.

(As a side question could I use a shared pool for all calls without the invokeAll calls messing each other?)

Upvotes: 2

Views: 4073

Answers (2)

Alex Filatov
Alex Filatov

Reputation: 5052

There can be many of these ParallelUtils running at the same time (launched from different threads)

Apparently at least one of these threads is interrupted either directly via Thread.interrupt() or indirectly via e.g. Future.cancel(true) or ExecutorService.shutdownNow().

Example to reproduce this interrupt:

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

Upvotes: 2

Stephen C
Stephen C

Reputation: 719446

What can cause ExecutorService.invokeAll() to throw an InterruptedException?

See the javadoc for shutdownNow():

There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. For example, typical implementations will cancel via Thread.interrupt(), so any task that fails to respond to interrupts may never terminate.

Since invokeAll waits until all tasks in the have been completed, calling shutdownNow() from another thread is one way that an invokeAll call could be interrupted.


However, in the code as you have shown it to us, there are no calls to shutdownNow() and no obvious way for the executor service object to leak to another thread.

It is also possible that something in your code (or some other library code) is calling Thread.interrupt. For example, one of the tasks might be doing this to itself.

Upvotes: 2

Related Questions