Backend Development 10 min read

How to Detect When a ThreadPoolExecutor Has Finished All Tasks in Java

This article compares several practical techniques—using isTerminated after shutdown, comparing task counts, employing CountDownLatch, maintaining a manual counter, and checking Future.isDone—to reliably determine when a Java ThreadPoolExecutor has completed all submitted jobs, complete with code examples and pros and cons for each method.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
How to Detect When a ThreadPoolExecutor Has Finished All Tasks in Java

When working with a ThreadPoolExecutor you often need to know when all submitted tasks have finished. The article reviews five common approaches, provides sample code for each, and discusses their advantages and limitations.

1. isTerminated() after shutdown() The pool is first shut down with shutdown() and then a loop repeatedly checks isTerminated() until it returns true. private static void shutdownTest() throws Exception { for (int i = 0; i < 30; i++) { int index = i; pool.execute(() -> sleepMtehod(index)); } pool.shutdown(); while (!pool.isTerminated()) { Thread.sleep(1000); System.out.println("还没停止。。。"); } System.out.println("全部执行完毕"); } Pros: simple code, clear semantics. Cons: requires shutting down the pool, which is unsuitable when the pool is managed as a Spring bean and must stay alive.

2. Comparing getTaskCount() and getCompletedTaskCount() The loop waits until pool.getTaskCount() == pool.getCompletedTaskCount() . private static void taskCountTest() throws Exception { for (int i = 0; i < 30; i++) { int index = i; pool.execute(() -> sleepMtehod(index)); } while (!(pool.getTaskCount() == pool.getCompletedTaskCount())) { System.out.println("任务总数:" + pool.getTaskCount() + "; 已经完成任务数:" + pool.getCompletedTaskCount()); Thread.sleep(1000); System.out.println("还没停止。。。"); } System.out.println("全部执行完毕"); } Pros: does not require shutting down the pool. Cons: only works if no new tasks are submitted while the check is running.

3. CountDownLatch A CountDownLatch initialized with the number of tasks is decremented in each task; the main thread calls await() to block until the count reaches zero. private static void countDownLatchTest() throws Exception { CountDownLatch taskLatch = new CountDownLatch(30); for (int i = 0; i < 30; i++) { int index = i; pool.execute(() -> { sleepMtehod(index); taskLatch.countDown(); System.out.println("当前计数器数量:" + taskLatch.getCount()); }); } taskLatch.await(); System.out.println("全部执行完毕"); } Pros: elegant, works well when the pool is a shared bean. Cons: you must know the exact number of tasks in advance and handle exceptions so the latch is always decremented.

4. Manual shared counter A static integer is incremented under a ReentrantLock after each task; the main thread polls the counter until it reaches the expected total. private static int taskNum = 0; private static void staticCountTest() throws Exception { Lock lock = new ReentrantLock(); for (int i = 0; i < 30; i++) { int index = i; pool.execute(() -> { sleepMtehod(index); lock.lock(); taskNum++; lock.unlock(); }); } while (taskNum < 30) { Thread.sleep(1000); System.out.println("还没停止。。。当前完成任务数:" + taskNum); } System.out.println("全部执行完毕"); } Pros: flexible for custom scenarios. Cons: requires explicit knowledge of task count and extra locking code, offering little benefit over CountDownLatch.

5. Future.isDone() Each task is submitted with submit() to obtain a Future ; the main thread polls future.isDone() until it returns true. private static void futureTest() throws Exception { Future future = pool.submit(() -> sleepMtehod(1)); while (!future.isDone()) { Thread.sleep(500); System.out.println("还没停止。。。"); } System.out.println("全部执行完毕"); } This approach is rarely used for termination detection because Future is intended to retrieve a single task’s result rather than monitor an entire pool.

Finally, the article notes that if the pool’s worker threads are non‑daemon, the JVM will not exit after the main method finishes, which explains why a program may appear to hang after all tasks complete.

JavaconcurrencythreadpoolThreadPoolExecutorFutureCountDownLatch
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.