skip to content

Why must setDaemon(true) be called before start(), and what does a freshly created thread's daemon status default to?

level: middleimportance: nice to knowfreq 35%

answer

  1. Flag feeds JVM shutdown bookkeeping
  2. Settable only in NEW state (before start)
  3. Late call -> IllegalThreadStateException
  4. Default = inherit creator's daemon flag
  5. Daemon thread spawns daemon children

basics

~20 s

Once a thread is running, the JVM has already decided whether it counts toward keeping the program alive, so you can't change it — calling setDaemon after start() throws IllegalThreadStateException. A new thread defaults to the daemon status of whichever thread created it.

solid answer

~50 s

The daemon flag affects the JVM's shutdown bookkeeping — whether this thread counts as a thread that keeps the process alive. That decision must be fixed before the thread actually runs, so setDaemon can only be called while the thread is in the NEW state, before start(). Calling it on an already-started (or terminated) thread throws IllegalThreadStateException, because allowing a live thread to flip between counting and not-counting toward JVM liveness would create races in shutdown logic. As for the default: a thread does not default to user-thread unconditionally — it inherits the daemon status of the creating thread. Since the main thread is a user thread, threads created from main are user threads unless you call setDaemon(true). But a thread spawned by a daemon thread is itself a daemon by default. This inheritance matters for thread pools and frameworks: if a daemon worker creates more threads, those are daemons too unless overridden.

go deeper

for a junior

Knows setDaemon must be called before start() and that doing it after throws an exception.

for a middle

Explains why the flag is locked to the NEW state (shutdown bookkeeping) and that the default is inherited from the creating thread, not fixed.

for a senior

Connects the inheritance rule to ThreadFactory/pool design, ensuring pool threads have intentional daemon status, and names IllegalThreadStateException precisely.

for a principal

Reasons about liveness/shutdown invariants the flag protects and standardizes daemon policy across an application's thread factories to avoid accidental process-exit data loss.

## Setup: thread states A Java `Thread` moves through a lifecycle. Right after `new Thread(...)` it is in the **NEW** state — created but not yet executing. Calling **`start()`** transitions it to **RUNNABLE** and actually begins running its `run()` method on a separate execution path. Once started, a thread can never go back to NEW and can never be started again. ## What the daemon flag controls The **daemon flag** is a boolean on each thread that tells the JVM whether this thread is a *background* (daemon) thread or a *foreground* (user) thread. The JVM keeps a running notion of how many **non-daemon (user) threads** are alive; when that count hits zero, the JVM shuts down. So the daemon flag is an input to the JVM's **shutdown bookkeeping**. ## Why it must be set before start() Because the flag participates in liveness counting, it must be decided **before** the thread begins to run. If you could flip the flag on a thread that is already executing, you could change — mid-flight — whether it counts toward keeping the JVM alive. That would race against the JVM's shutdown check ("are there any user threads left?"). To avoid that ambiguity, Java fixes the flag at the NEW state only. Concretely, `setDaemon(boolean)` checks the thread's state. If the thread is not NEW (it has been started, or has already terminated), it throws **`IllegalThreadStateException`** — an unchecked exception signaling the thread is in the wrong state for this operation. ```java Thread t = new Thread(task); t.start(); t.setDaemon(true); // throws IllegalThreadStateException ``` ## The default: inheritance, not a fixed value A common misconception is "new threads are always user threads." The truth: a new thread **inherits the daemon status of the thread that constructs it**. The mechanism: in the `Thread` constructor, the JVM reads `Thread.currentThread().isDaemon()` and copies it into the new thread. - The **main** thread is created by the JVM as a **user** thread. - Therefore threads you create *from* main are user threads by default. - But a thread created *by a daemon thread* is a **daemon** by default. This is easy to forget inside thread pools or background frameworks: if a daemon worker thread spawns helper threads without calling `setDaemon(false)`, those helpers are daemons too, and may be abandoned at JVM exit. ## Practical takeaways 1. Set the flag immediately after construction, before `start()`. 2. Don't assume a default — be explicit when correctness depends on it. 3. In `ThreadFactory` implementations (used by `ExecutorService`), set `setDaemon(...)` deliberately so pool threads have a known, intentional liveness behavior.

  • A daemon background worker creates a new Thread without calling setDaemon. Is the new thread a daemon?
    Yes. The new thread inherits the daemon status of its creator, and the creator is a daemon, so the child is a daemon unless explicitly set to false.

saying these in an interview costs you the question

  • Claiming new threads are unconditionally user threads (they inherit)
  • Thinking setDaemon throws a checked exception
  • Believing you can toggle daemon status on a live thread
  • Forgetting that pool/framework threads created by daemons are daemons too

context