Executorservice, How to Wait for All Tasks to Finish

Wait for all tasks in ExecutorService.execute to complete

If you read the javadoc of the ExecutorService.awaitTermination (or look at the method signature) you will see it returns a boolean. This boolean indicates if the Executor terminated or not. You can use that information to create a while loop to determine if it has been terminated or not.

ExecutorService executor = ...

executor.shutdown(); // close the executor and don't accept new tasks

while (!executor.awaitTermination(100, TimeUnit.MILLISECONDS) {}

Something like this will stop the executor and wait until it terminated and all tasks have finished.

How to wait for all threads to finish, using ExecutorService?

Basically on an ExecutorService you call shutdown() and then awaitTermination():

ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
taskExecutor.execute(new MyTask());
}
taskExecutor.shutdown();
try {
taskExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
...
}

Java executor service: Waiting for all tasks to finish

try-with-resources in Project Loom

You asked:

What I want to achieve is that 'while' loop goes to next iteration only when all tasks submitted to executor in current iteration are finished.

Project Loom promises to make this simpler.

One of the changes brought by Project Loom is that the ExecutorService interface is a sub-interface of AutoCloseable. This means we can use try-with-resources syntax. The try-with-resources automatically blocks until all submitted tasks are done/failed/canceled — just what you asked for.

Also, the executor service is automatically shut down when exiting the try. These changes mean your code becomes simpler and clearer.

Also, for code that blocks often, such as database access, you will see dramatically faster performance using virtual threads (a.k.a. fibers). Virtual threads is another new feature of Project Loom. To get this feature, call Executors.newVirtualThreadExecutor.

Experimental builds of Project Loom are available now, based on early-access Java 17. The Loom team is asking for feedback. For more info, see recent presentations and interviews by Ron Pressler of Oracle.

System.out.println( "INFO - executor service about to start. " + Instant.now() );
try (
ExecutorService executorService = Executors.newVirtualThreadExecutor() ;
)
{
for ( int i = 0 ; i < 7 ; i++ )
{
executorService.submit( ( ) -> System.out.println( Instant.now() ) );
}
}
// Notice that when reaching this point we block until all submitted tasks still running are fin
// because that is the new behavior of `ExecutorService` being `AutoCloseable`.
System.out.println( "INFO - executor service shut down at this point. " + Instant.now() );

When run.

INFO - executor service about to start. 2021-02-08T06:27:03.500093Z
2021-02-08T06:27:03.554440Z
2021-02-08T06:27:03.554517Z
2021-02-08T06:27:03.554682Z
2021-02-08T06:27:03.554837Z
2021-02-08T06:27:03.555015Z
2021-02-08T06:27:03.555073Z
2021-02-08T06:27:03.556675Z
INFO - executor service shut down at this point. 2021-02-08T06:27:03.560723Z

Await completion of all ExecutorService Threads

When I executed the code above, I was expecting the code to await the completion of the previous threads when running "threadPool.shutdown()"

this won't happen, from ExecutorService's docs:

void shutdown()

Initiates an orderly shutdown in which previously submitted tasks are
executed, but no new tasks will be accepted. Invocation has no
additional effect if already shut down.

This method does not wait for previously submitted tasks to complete
execution
. Use awaitTermination to do that.

in order to achieve your result, you need to use both, shutdown() first and then awaitTermination​():

boolean awaitTermination​(long timeout, TimeUnit unit) throws
InterruptedException

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

returns:
true if this executor terminated and false if the timeout elapsed before termination

this behaviour:

I tried using threadPool.awaitTermination(30, TimeUnit.SECONDS)
instead but for a reason I ignore yet, it awaits the full completion
of the 30 seconds before continuing even if all letters have been
printed.

was probably caused by replacing shutdown() with awaitTermination​(). it was waiting on a "non-shutdown" pool. as already said, you need to call shutdown() before awaitTermination​().

How to wait for all tasks in an ThreadPoolExecutor to finish without shutting down the Executor?

If you are interested in knowing when a certain task completes, or a certain batch of tasks, you may use ExecutorService.submit(Runnable). Invoking this method returns a Future object which may be placed into a Collection which your main thread will then iterate over calling Future.get() for each one. This will cause your main thread to halt execution until the ExecutorService has processed all of the Runnable tasks.

Collection<Future<?>> futures = new LinkedList<Future<?>>();
futures.add(executorService.submit(myRunnable));
for (Future<?> future:futures) {
future.get();
}

How to correctly implement executor that runs multiple iterations and waits for all tasks to complete and successfully terminates after tasks are done

With reference to ThreadPoolExecutor documentation. The awaitTermination() method description reads:

Blocks until all tasks have completed execution after a shutdown request

While the shutdown() method descriptin reads

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

Which indicates that awaitTermination() call is effective after a shutdown() call.

To solve the above problem, shutdown() needs to be called first and then awaitTermination()

NOTE: I have not personally tested this; however, John has, as mentioned in the comment of the original post and the mechanism works

ExecutorService's shutdown() doesn't wait until all threads will be finished

The answer is available in the ExecutorService.shutdown() Javadoc:

This method does not wait for previously submitted tasks to complete execution. Use awaitTermination to do that.

If you want to wait for the threads to finish work you have the following options:

  • get Future instances returned by submit() and call get() on every Future instance
  • after calling shutdown on service call awaitTermination on service until it returns true
  • instead of calling submit on service add your Runnable instances to a java.util.List and pass this list to the invokeAll method called on service


Related Topics



Leave a reply



Submit