Card 07/ 09

GotchaDifficulty: Advanced1 min

Unclosed Thread Pools: Why a Program Hangs After main Returns

Every task completed, the summary is logged, and the process never exits.

A thread pool's threads are non-daemon by default, and they do not stop when their queue empties: they wait for more work. Because the Java virtual machine exits only when its last non-daemon thread finishes, a pool that is never shut down keeps the process alive after main returns.

The batch job finishes, logs its summary, and the process never exits. Every task completed, and the container has to be killed:

java
ExecutorService pool = Executors.newFixedThreadPool(4);

for (Path file : files) { pool.submit(() -> process(file)); }

System.out.println("done");

Four pool threads are waiting on an empty queue, and the virtual machine waits for them.

There are two fixes, and the second is the one to reach for in new code:

java
pool.shutdown();
pool.awaitTermination(1, TimeUnit.MINUTES);

// or, since Java 19
try (ExecutorService pool = Executors.newFixedThreadPool(4)) {
    for (Path file : files) { pool.submit(() -> process(file)); }
}

The try-with-resources form calls shutdown and then waits, so leaving the block means every task has finished. Whichever you use, a pool that nothing shuts down is a process that nothing can stop.