Daemon Thread in Java – Background Threads Explained
A daemon thread is a low-importance background thread that does not prevent the JVM from exiting. When all user (non-daemon) threads have finished, the JVM shuts down and simply abandons any daemon threads still running. The garbage collector and other JVM housekeeping threads are daemon threads.
This tutorial explains user vs daemon threads, how to create a daemon with setDaemon(true), the rules involved, and the important risk that a daemon thread can be stopped mid-task without running its finally blocks.
1. User Threads vs Daemon Threads
| Aspect | User thread | Daemon thread |
|---|---|---|
| Keeps the JVM alive | Yes: the JVM waits for it | No: abandoned at exit |
| Typical work | The application's real tasks | Background services: monitoring, cache cleanup, heartbeats |
| Default for | main and threads created by user threads | Threads created by daemon threads; JVM internal threads; virtual threads |
| Clean shutdown | Finishes normally | May stop abruptly, skipping finally blocks |
2. Creating a Daemon Thread
Call setDaemon(true) before start(). This heartbeat thread loops forever, yet the program ends as soon as main finishes:
public class DaemonDemo {
public static void main(String[] args) throws InterruptedException {
Thread heartbeat = new Thread(() -> {
int beat = 0;
while (true) { // never ends on its own
System.out.println("heartbeat " + (++beat));
try { Thread.sleep(100); } catch (InterruptedException e) { return; }
}
}, "heartbeat");
heartbeat.setDaemon(true); // must be set BEFORE start()
heartbeat.start();
Thread.sleep(350); // main does its work
System.out.println("main finished; JVM exits and the daemon is stopped");
}
}
heartbeat 1 heartbeat 2 heartbeat 3 heartbeat 4 main finished; JVM exits and the daemon is stopped
Without setDaemon(true), the heartbeat thread would keep the program running forever.
3. User Threads Keep the JVM Alive
public class UserThreadKeepsAlive {
public static void main(String[] args) {
Thread user = new Thread(() -> {
try { Thread.sleep(300); } catch (InterruptedException e) { }
System.out.println("user thread: finished its work, now the JVM may exit");
});
user.start(); // non-daemon (user) thread
System.out.println("main: returning from main()");
// The JVM waits for the user thread before exiting
}
}
main: returning from main() user thread: finished its work, now the JVM may exit
Even though main() returned first, the JVM waited for the user thread to finish.
4. Rules of Daemon Threads
public class DaemonRules {
public static void main(String[] args) throws InterruptedException {
System.out.println("main is daemon? " + Thread.currentThread().isDaemon());
Thread daemon = new Thread(() -> {
Thread child = new Thread(() -> { });
System.out.println("child of daemon is daemon? " + child.isDaemon()); // inherited
});
daemon.setDaemon(true);
daemon.start();
daemon.join();
Thread running = new Thread(() -> {
try { Thread.sleep(200); } catch (InterruptedException e) { }
});
running.start();
try {
running.setDaemon(true); // too late
} catch (IllegalThreadStateException e) {
System.out.println("setDaemon after start(): " + e.getClass().getSimpleName());
}
running.join();
Thread v = Thread.ofVirtual().unstarted(() -> { });
System.out.println("virtual thread is daemon? " + v.isDaemon());
}
}
main is daemon? false child of daemon is daemon? true setDaemon after start(): IllegalThreadStateException virtual thread is daemon? true
setDaemonmust be called beforestart(); afterwards it throwsIllegalThreadStateException.- A new thread inherits the daemon status of the thread that creates it.
- The
mainthread is a user thread. - Virtual threads are always daemon threads; their daemon status cannot be changed to false.
isDaemon()reports a thread's status.
5. The Risk: Work Can Be Cut Off
When the JVM exits, daemon threads are stopped wherever they are. Their finally blocks do not run:
public class DaemonFinallyLost {
public static void main(String[] args) throws InterruptedException {
Thread writer = new Thread(() -> {
try {
System.out.println("daemon: writing a file...");
Thread.sleep(5_000);
System.out.println("daemon: done"); // never printed
} catch (InterruptedException e) {
} finally {
System.out.println("daemon: finally - closing file"); // never printed either!
}
});
writer.setDaemon(true);
writer.start();
Thread.sleep(200);
System.out.println("main: exiting without waiting");
}
}
daemon: writing a file... main: exiting without waiting
Neither "done" nor the finally message appeared. Never use daemon threads for work that must complete or clean up, such as writing files, committing transactions or sending messages. Use user threads (or an executor you shut down gracefully) for those.
6. Good Use Cases
- Periodic monitoring, metrics collection and heartbeats.
- Cleaning expired cache entries.
- Background prefetching or warm-up that can safely be abandoned.
- Timers:
new Timer(true)creates a daemon timer thread.
For executor-based daemon threads, supply a ThreadFactory such as Thread.ofPlatform().daemon(true).factory().
7. Summary
- Daemon threads are background threads that do not keep the JVM running.
- Mark a thread as daemon with
setDaemon(true)before starting it. - Daemon status is inherited;
mainis a user thread; virtual threads are always daemon. - Daemon threads can be stopped abruptly without running
finally, so use them only for expendable work.
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What is a daemon thread in Java?
A background thread that does not prevent the JVM from exiting. When only daemon threads remain, the JVM shuts down.
Q2. How do I create a daemon thread?
Create a thread and call setDaemon(true) before start().
Q3. What happens if setDaemon is called after start()?
It throws IllegalThreadStateException.
Q4. Is the main thread a daemon thread?
No. It is a user thread.
Q5. What is the difference between a user thread and a daemon thread?
The JVM waits for user threads to finish before exiting, but abandons daemon threads.
Q6. Do finally blocks run in daemon threads at JVM exit?
No. Daemon threads are stopped without unwinding their stacks, so their finally blocks and try-with-resources clean-up do not run.
Q7. Is the garbage collector a daemon thread?
Yes. GC and other JVM housekeeping threads run as daemon threads.
Q8. Is daemon status inherited?
Yes. A thread created by a daemon thread is a daemon by default; one created by a user thread is a user thread.
Q9. Are virtual threads daemon threads?
Yes, always. setDaemon(false) on a virtual thread throws IllegalArgumentException.
Q10. How do I check whether a thread is a daemon?
Call thread.isDaemon().
Q11. Can a daemon thread be converted to a user thread?
Only before it is started, by calling setDaemon(false). Platform threads only; virtual threads are always daemon.
Q12. Do daemon threads have lower priority?
No. Priority and daemon status are independent.
Q13. When should I use a daemon thread?
For background work that may be abandoned at any time, such as monitoring, heartbeats or cache cleanup.
Q14. Are thread pool threads daemon threads?
Executors factory methods create user threads by default, which is why you must shut down executors. Supply a custom ThreadFactory for daemon threads.
Q15. Do shutdown hooks run when daemon threads are abandoned?
Yes. Shutdown hooks registered with Runtime.addShutdownHook run during normal JVM shutdown, while daemon threads are simply abandoned.
Q16. Why does my program never exit?
A user thread is still running, often an executor that was never shut down. Make background threads daemon or shut executors down.
Q17. Can a daemon thread create user threads?
Yes, by calling setDaemon(false) on the new thread before starting it. That user thread will keep the JVM alive.
Q18. What does "daemon" mean?
The term comes from Unix, where daemons are background service processes that run without user interaction.
Q19. Is Timer's thread a daemon?
Only if you create it with new Timer(true). The default constructor uses a user thread.
Q20. What happens to a daemon thread holding a lock at exit?
The JVM terminates anyway; since the whole process ends, the lock no longer matters, but any partially written external data may be left inconsistent.