Once the executor service is shut down, it won’t wait for the completion of the threads in it. Hence, one of the ways to wait for the completion of the threads when the executor service is shut down is two-phase termination.
The steps involved in the two-phase termination are as follows:
shutdown()
method is invoked. This prevents from new tasks being submitted to the pool.awaitTermination()
method is invoked with a timeout of n seconds. This call will block until the pool terminates or the timeout occurs.shutdownNow()
method is invoked to cancel any remaining tasks.awaitTermination()
method is invoked again with n seconds.Ideally, by the fourth step, the pool should terminate. In case the pool doesn’t terminate after the fourth step, then we must inspect what’s going wrong!
import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;public class Main{public static void main(String[] args) throws InterruptedException {final ExecutorService threadPool = Executors.newFixedThreadPool(10);for (int i = 0; i < 100; i++) {threadPool.execute(() -> {if (threadPool.isShutdown()) {System.out.println("Pool is terminating.");}try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {System.out.println("WARN: Task interrupted");}System.out.println("Doing work.");});}threadPool.shutdown();if (!threadPool.awaitTermination(2, TimeUnit.SECONDS)) {threadPool.shutdownNow();if (!threadPool.awaitTermination(2, TimeUnit.SECONDS)) {System.out.println("The pool did not terminate");}}}}
Lines 1–3: We import the relevant classes.
Line 8: We create a fixed thread pool with 10 threads.
Lines 10–21: In a for
loop, we submit runnables to the thread pool. The runnable does the following:
We check if the thread pool is shut down. If yes, we print "Pool is terminating"
.
We put the current thread that executes the runnable to sleep. If the thread is interrupted, a warning is printed saying WARN: Task interrupted
.
If none of the above two situations are reached, Doing work.
is printed to indicate that the task/runnable is executing.
Line 24: We invoke the shutdownNow()
method on the executor service/thread pool.
Lines 25–30: We implement the two-phase termination process described above.