Back to Daemon Threads & JVM Shutdown
Q1Question 1 of 3

What are daemon threads?

Key Concepts
  • A daemon thread is a background service thread that does not prevent the JVM from exiting.
  • The JVM terminates when all non-daemon (user) threads finish, killing daemon threads abruptly.
  • Call setDaemon(true) before start(); calling it after start() throws IllegalThreadStateException.
  • Child threads inherit the daemon status of their parent thread.
  • The garbage collector and JMX threads are daemon threads; the main thread is non-daemon.
  • Finally blocks in daemon threads may not execute on JVM exit, so do not rely on them for critical cleanup.

Definition

A daemon thread is a background service thread that does not prevent the JVM from exiting; when all non-daemon threads finish, the JVM terminates and kills all daemon threads abruptly without running their finally blocks.
  • Daemon thread – a background thread that does not prevent JVM exit; set via thread.setDaemon(true) before start().
  • Non-daemon (user) thread – a foreground thread that keeps the JVM alive as long as it is running.
  • JVM exit rule – the JVM terminates when all non-daemon threads finish, killing all daemon threads immediately.
  • Inheritance – a new thread inherits the daemon status of its parent thread.
  • IllegalThreadStateException – thrown if setDaemon() is called after start().
  • Finally blocks – may not execute in daemon threads during JVM shutdown, so critical cleanup should use shutdown hooks instead.

At National Bank of India, non-daemon threads are the bank tellers serving customers. The bank stays open as long as at least one teller is working. Daemon threads are the cleaning crew working in the background: sweeping floors, restocking forms, refreshing water coolers. When the last teller finishes and goes home, the bank closes immediately. The cleaning crew is kicked out mid-sweep with no chance to finish. Use daemons for background tasks that are safe to abandon.

Understanding the Concepts

What is a daemon thread?

A daemon thread is a background service thread that the JVM does not wait for. When all non-daemon threads have terminated, the JVM exits, killing all daemon threads abruptly. Daemon threads are used for housekeeping tasks that should stop automatically when the application shuts down.

JAVA
package com.bank.service;

public class DaemonThreadDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread cacheRefresher = new Thread(() -> {
            while (true) {
                try {
                    System.out.println("Refreshing exchange rate cache...");
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }, "cache-refresher");

        cacheRefresher.setDaemon(true); // MUST be before start()
        cacheRefresher.start();

        Thread.sleep(2500); // main thread sleeps 2.5 seconds
        System.out.println("Main thread done. JVM will exit.");
        // cache-refresher is daemon: JVM exits without waiting for it
    }
}
TEXT
Refreshing exchange rate cache...
Refreshing exchange rate cache...
Refreshing exchange rate cache...
Main thread done. JVM will exit.

How is a daemon thread different from a user thread?

| Feature | Daemon Thread | User (Non-Daemon) Thread |
|---|---|---|
| Prevents JVM exit | No | Yes |
| Default | Inherits from parent | main thread is non-daemon |
| Finally blocks on shutdown | May not execute | Execute normally |
| Use case | Background housekeeping | Critical business logic |
| Created by | setDaemon(true) before start() | Default (no call needed) |

What are the rules for daemon threads?

There are four rules to remember:

  1. Call setDaemon(true) before start(). Calling it after throws IllegalThreadStateException.
  2. Child threads inherit the daemon status of their parent.
  3. The main thread is non-daemon.
  4. The JVM exits when all non-daemon threads terminate.
JAVA
// Rule 1: setDaemon after start throws exception
Thread t = new Thread(() -> {});
t.start();
try {
    t.setDaemon(true); // IllegalThreadStateException!
} catch (IllegalThreadStateException e) {
    System.out.println("Cannot change daemon status after start");
}

// Rule 2: child inherits parent's daemon status
Thread parent = new Thread(() -> {
    Thread child = new Thread(() -> {});
    System.out.println("Child daemon: " + child.isDaemon()); // same as parent
});
parent.setDaemon(true);
parent.start();

How do you create a daemon thread pool?

Use a custom ThreadFactory that sets daemon status on every worker thread.

JAVA
package com.bank.service;

import java.util.concurrent.*;

public class DaemonPoolDemo {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(4, r -> {
            Thread t = new Thread(r);
            t.setDaemon(true);
            t.setName("daemon-worker-" + t.getId());
            return t;
        });

        pool.submit(() -> System.out.println(
            Thread.currentThread().getName() + " processing"));

        // Pool threads are daemon: JVM exits when main finishes
        // Good for optional background processing
        // Bad for critical work that MUST complete
    }
}

Why are finally blocks not guaranteed in daemon threads?

When the JVM exits because all non-daemon threads are done, daemon threads are killed immediately. The JVM does not run their finally blocks or shutdown hooks attached to those threads.

JAVA
Thread daemon = new Thread(() -> {
    try {
        Thread.sleep(Long.MAX_VALUE);
    } finally {
        // MAY NOT EXECUTE if JVM exits!
        System.out.println("Saving critical data...");
    }
});
daemon.setDaemon(true);
daemon.start();
// If all user threads end, JVM exits, finally is SKIPPED

For critical cleanup, use Runtime.addShutdownHook() instead.

When should you use daemon threads?

  • Use daemon for background tasks where abrupt termination is acceptable:
  • Cache refresh and warming
  • Heartbeat monitoring
  • Log rotation and periodic flushing
  • Metrics collection
  • Background cleanup
  • Use non-daemon for tasks that must complete:
  • Trade settlement and payment processing
  • Database writes and data migration
  • File generation and report creation

What about the garbage collector?

The garbage collector runs as a daemon thread. It stops automatically when the JVM exits. This is why GC does not prevent JVM shutdown.

What are common mistakes with daemon threads?

JAVA
// WRONG: critical work on daemon thread
Thread t = new Thread(() -> settleAllPendingTrades());
t.setDaemon(true); // trades may be lost on JVM exit!
t.start();

// WRONG: relying on finally in daemon for cleanup
Thread t2 = new Thread(() -> {
    try { process(); }
    finally { flushAuditLog(); } // may not run!
});
t2.setDaemon(true);

// CORRECT: use shutdown hook for critical cleanup
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
    flushAuditLog(); // runs on SIGTERM, SIGINT
}));

What are common interview follow-up questions?

  • Can a daemon thread create a non-daemon thread? Yes, by explicitly calling setDaemon(false) on the child before start().
  • What happens to daemon threads during System.exit()? The JVM runs shutdown hooks, then terminates daemon threads.
  • Is the main thread a daemon? No, the main thread is always non-daemon.

Visual Overview

DIAGRAM
  JVM Exit Decision

  ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
  │ User Thread  │     │ User Thread  │     │ Daemon      │
  │ (main)       │     │ (worker-1)   │     │ (GC, cache) │
  └──────┬──────┘     └──────┬──────┘     └──────┬──────┘
         │                    │                    │
         ▼                    ▼                    │
    main() ends         worker finishes            │
         │                    │                    │
         ▼                    ▼                    │
  ┌──────────────────────────────────┐             │
  │ All user threads finished?       │             │
  │ YES → JVM exits                  │─────────────┘
  │       Daemon threads KILLED      │  (abrupt, no
  │       finally blocks SKIPPED     │   cleanup)
  └──────────────────────────────────┘

Key Takeaway

A daemon thread is a background service thread that the JVM does not wait for. When all non-daemon (user) threads terminate, the JVM exits immediately, killing all daemon threads without running their finally blocks. The garbage collector, JMX threads, and other JVM internal services are daemon threads.

The rules are straightforward. Call setDaemon(true) before start(). Child threads inherit their parent's daemon status. The main thread is non-daemon. The JVM exit condition is simple: no more non-daemon threads means shutdown.

Use daemon threads for background housekeeping that is safe to abandon: cache refresh, heartbeat monitoring, metrics collection. Use non-daemon threads for critical business logic that must complete: trade settlement, payment processing, data writes. Never put critical cleanup in a finally block inside a daemon thread, because JVM exit can skip it. Use Runtime.addShutdownHook() for critical shutdown logic instead.

At National Bank of India, the cache refresher and heartbeat monitor run as daemon threads. They stop automatically when the trading service shuts down. The log flusher was initially a daemon, but it lost the last five seconds of logs on shutdown. Moving the critical flush to a shutdown hook fixed the problem.

Remember one sentence: daemon threads die when the last user thread exits, so never run critical work on them.

---

Share
Use ← → arrow keys to navigate