shutdown() vs shutdownNow() vs awaitTermination() — how d… — Cracked Java
// Concurrency & Multithreading · Executors & Thread Pools
MidTheory

shutdown() vs shutdownNow() vs awaitTermination() — how do you stop a pool cleanly?

shutdown() is a graceful stop — it stops accepting new tasks but lets already-submitted ones finish. shutdownNow() is an abrupt stop — it interrupts running tasks and abandons the queue. Neither blocks; awaitTermination() is the separate call that actually waits for the pool to drain.

The three methods

  • shutdown() — transitions the pool to SHUTDOWN. New submissions are rejected (RejectedExecutionException), but queued and in-flight tasks run to completion. Non-blocking; returns immediately.
  • shutdownNow() — transitions to STOP. Drains and returns the queued-but-not-started tasks as a List<Runnable>, and calls Thread.interrupt() on every worker. Tasks only actually stop if their code is responsive to interruption.
  • awaitTermination(timeout, unit) — blocks until all tasks finish, the timeout elapses, or the current thread is interrupted. Returns true if the pool terminated within the window.

The correct shutdown idiom

void shutdownGracefully(ExecutorService pool) {
    pool.shutdown();                              // stop taking new work
    try {
        if (!pool.awaitTermination(30, TimeUnit.SECONDS)) {
            List<Runnable> dropped = pool.shutdownNow();   // force interrupt
            log.warn("Forcing shutdown, {} tasks never started", dropped.size());
            if (!pool.awaitTermination(10, TimeUnit.SECONDS)) {
                log.error("Pool did not terminate");
            }
        }
    } catch (InterruptedException e) {
        pool.shutdownNow();
        Thread.currentThread().interrupt();       // restore the flag
    }
}

The pattern is: request graceful shutdown, wait a bounded time, escalate to shutdownNow(), then wait again.

On Java 19+, ExecutorService implements AutoCloseable, so try-with-resources calls close(), which is effectively shutdown() plus awaitTermination until done — convenient for short-lived pools.

Mark your status