Safely Shut Down a Java ThreadPool with Daemon Threads for Asynchronous Tasks
This article explains how to create a fixed-size Java thread pool, attach a daemon thread that monitors the main thread, and use Phaser for synchronization, providing complete Groovy and Java examples with detailed code and console output.
In the previous article the author introduced a custom asynchronous keyword that accepts a closure and runs it in a separate thread. When applying this idea in real projects, thread‑pool configuration becomes critical, especially when the core pool size is greater than one or when the work queue size is mis‑configured.
Idea
A daemon thread is used to monitor the main thread and automatically shut down the asynchronous thread pool after the main method finishes. The pool is a fixed‑size executor with 16 threads, and the work queue is set to a large capacity (e.g., 100 000 or 1 000 000) to avoid blocking.
Step‑by‑step implementation
Create the thread pool
private static volatile ExecutorService funPool;
static ExecutorService getFunPool() {
if (funPool == null) {
synchronized (ThreadPoolUtil.class) {
if (funPool == null) {
funPool = createFixedPool(Constant.POOL_SIZE);
daemon();
}
}
}
return funPool;
}Create the daemon thread
static boolean daemon() {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while (checkMain()) {
SourceCode.sleep(1.0);
}
ThreadPoolUtil.shutFun();
}
});
thread.setDaemon(true);
thread.setName("FT-D");
thread.start();
logger.info("Daemon thread:{} started!", thread.getName());
return true;
}Check whether the main thread is alive
static boolean checkMain() {
int count = Thread.activeCount();
ThreadGroup group = Thread.currentThread().getThreadGroup();
Thread[] threads = new Thread[count];
group.enumerate(threads);
for (int i = 0; i < count; i++) {
if (threads[i].getName().equals("main")) {
return true;
}
}
return false;
}Testing the asynchronous pool
Groovy test script (using the "times" sugar)
public static void main(String[] args) {
20.times {
def a = it as String
fun {
sleep(1.0)
output(StringUtil.right("index:" + a, 10) + Time.getNow())
}
}
}Equivalent Java version
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
Integer a = i;
fun(() -> {
sleep(1.0);
output(StringUtil.right("index:" + a, 10) + Time.getNow());
return null;
});
}
}The console output shows each asynchronous task printing its index and timestamp, followed by a final warning line indicating that the daemon thread has closed the pool, which matches the expected behavior.
Thread synchronization with Phaser
To coordinate the completion of all asynchronous tasks, the article uses java.util.concurrent.Phaser. The Groovy and Java examples below demonstrate passing the phaser to the fun method.
Groovy version
public static void main(String[] args) {
def phaser = new Phaser(1)
20.times {
def a = it as String;
fun {
sleep(1.0);
output(StringUtil.right("index:" + a, 10) + Time.getNow());
}, phaser;
}
phaser.arriveAndAwaitAdvance();
}Java version
public static void main(String[] args) {
Phaser phaser = new Phaser(1);
for (int i = 0; i < 20; i++) {
Integer a = i;
fun(() -> {
sleep(1.0);
output(StringUtil.right("index:" + a, 10) + Time.getNow());
return null;
}, phaser);
}
phaser.arriveAndAwaitAdvance();
}The final console logs again end with the daemon thread’s warning, confirming that the pool is closed only after all tasks have synchronized on the phaser.
Conclusion
Using a daemon thread to monitor the main thread provides a clean way to release resources for a custom asynchronous framework. Setting a sufficiently large work queue prevents task rejection, while Phaser offers a simple barrier for multi‑thread synchronization. The provided code snippets can be directly integrated into Java or Groovy projects that require high‑throughput batch execution.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
