Kirill
Kirill

Reputation: 1610

How to shutdown CompletionService after completing currently executed tasks

I have something like this:

ExecutorService executor = Executors.newFixedThreadPool(2);
CompletionService<Boolean> completionService = new ExecutorCompletionService<>(executor);
int i = 0;
while (i < 40) {
  completionService.submit(getTask());
  i++;
}
executor.shutdown();
System.out.println("SHUTDOWN");

After calling shutdown all submitted tasks are executed. If I call shutdownNow, then currently executed threads are throws java.lang.InterruptedException.

Is there are any way to wait currently executed tasks to complete and don't execute other submitted tasks?

Upvotes: 2

Views: 1616

Answers (3)

Adam Michalik
Adam Michalik

Reputation: 9945

shutdown() allows the currently submitted tasks to complete, but rejects new ones:

Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted.

If you want to wait in your main thread for the executor to shut down, you can invoke executor.awaitTermination(long timeout, TimeUnit unit):

Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens first.

If you want to allow the tasks that are currently running to complete, but discard the ones that are already submitted to the queue, you have a few choices:

  • cancelling the Futures with cancel(false):

    Attempts to cancel execution of this task. This attempt will fail if the task has already completed, has already been cancelled, or could not be cancelled for some other reason. If successful, and this task has not started when cancel is called, this task should never run.

    Returns: false if the task could not be cancelled, typically because it has already completed normally; true otherwise

  • wrapping your Runnable/Callable with a custom CancellableRunnable/Callable (depending on what your getTask() returns):

    class CancellableRunnable implements Runnable {
    
        private final AtomicBoolean shouldRun;
        private final Runnable delegate;
    
        public CancellableRunnable(AtomicBoolean shouldRun, Runnable delegate) {
            this.shouldRun = shouldRun;
            this.delegate = delegate;
        }
    
        @Override
        public void run() {
            if (shouldRun.get()) {
                delegate.run();
            }
        }
    }
    

    and the usage in your example:

    AtomicBoolean shouldRun = new AtomicBoolean(true);
    while (i < 40) {
      completionService.submit(new CancellableRunnable(shouldRun, getTask()));
      i++;
    }
    shouldRun.set(false);
    executor.shutdown();
    

Upvotes: 4

assylias
assylias

Reputation: 328598

If all you want is the first two results and then discard the other tasks, you can wait for the first two tasks to be completed then cancel the others, for example by calling shutdownNow if you don't need the completion service any longer.

Future<Boolean> result1 = copmletionService.take();
Future<Boolean> result2 = copmletionService.take();
completionService.shutdownNow();

Upvotes: 0

Anonymous
Anonymous

Reputation: 86282

Yes, after you have called shutdown(), the executor will accept no new tasks. Next you call awaitTermination() to await running tasks completing.

Upvotes: 0

Related Questions