Daemon threads and thread factories

Multithreading · lesson 31 of 38 · 3 min read

Decide which threads keep the JVM alive, name them properly, and catch what escapes them.

Open this lesson in the learning hub

Key points

  • The JVM exits when the last non-daemon thread ends. Daemon threads are then killed outright, with no finally blocks.
  • setDaemon(true) must be called before start(). Use it for background helpers, never for work that must complete.
  • A new thread inherits the daemon flag and the priority of the thread that created it.
  • Give threads names with a ThreadFactory. Unnamed pool threads turn every thread dump into guesswork.
  • An exception escaping a task kills only that thread, and quietly. Set an uncaught exception handler so it is at least logged.

Example

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread.setDefaultUncaughtExceptionHandler(
                (t, e) -> System.out.println("uncaught in " + t.getName() + " : " + e.getMessage()));

        Thread boom = new Thread(() -> { throw new IllegalStateException("task blew up"); }, "boom");
        boom.start();
        boom.join();                       // only that thread died, the JVM carried on

        Thread heartbeat = new Thread(() -> { for (int i = 0; i < 40; i++) sleep(50); }, "heartbeat");
        heartbeat.setDaemon(true);         // must be set BEFORE start()
        heartbeat.start();

        ThreadFactory named = new ThreadFactory() {
            private final AtomicInteger n = new AtomicInteger(1);
            @Override public Thread newThread(Runnable r) {
                Thread t = new Thread(r, "orders-" + n.getAndIncrement());
                t.setDaemon(false);        // real work: keep the JVM alive until it finishes
                return t;
            }
        };

        ExecutorService pool = Executors.newFixedThreadPool(2, named);
        for (int i = 0; i < 3; i++) {
            pool.execute(() -> System.out.println("job ran on   : " + Thread.currentThread().getName()));
        }
        pool.shutdown();
        pool.awaitTermination(2, TimeUnit.SECONDS);

        System.out.println("heartbeat    : daemon=" + heartbeat.isDaemon() + ", alive=" + heartbeat.isAlive());
        System.out.println("main ends    : the JVM exits anyway and the daemon dies with it");
    }

    static void sleep(long ms) { try { Thread.sleep(ms); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }
}

Name every thread, and make it a daemon only if losing its work is acceptable.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Multithreading course, and every lesson in it is listed on the Multithreading contents page.