setDaemon(true)必须在start()前调用,否则抛IllegalThreadStateException;守护线程不阻止JVM退出,仅剩守护线程时JVM立即终止,适用于监控、日志等后台任务。

在 Java 中,setDaemon(true) 用于将线程标记为守护线程(Daemon Thread),它必须在 start() 方法调用前设置,否则会抛出 IllegalThreadStateException。守护线程的核心作用是:当 JVM 中所有非守护线程(即用户线程)都结束时,JVM 会自动退出,不再等待守护线程执行完毕。
守护线程的设置时机和限制
守护线程只能在线程处于“新建状态”(NEW)时设置,一旦线程已启动(RUNNABLE 或之后的状态),再调用 setDaemon() 就会失败。
- ✅ 正确写法:
Thread t = new Thread(() -> {...}); t.setDaemon(true); t.start(); - ❌ 错误写法:
t.start(); t.setDaemon(true);—— 运行时报异常 - ⚠️ 注意:
main线程默认是非守护线程,且不能被设为守护线程(调用setDaemon(true)无效)
守护线程的典型用途
守护线程适合执行后台支持性任务,不参与业务逻辑的主流程,也不影响程序正常终止。
- 垃圾回收器线程就是 JVM 内置的守护线程
- 日志异步刷盘、监控心跳上报、连接池清理等可设为守护线程
- 避免因后台任务未完成而阻塞 JVM 退出 —— 比如一个定时打印日志的线程,若设为非守护线程,JVM 会一直等它下次执行完才退出
守护线程与非守护线程的生命周期差异
JVM 的退出条件只取决于是否存在活跃的非守护线程,与守护线程是否还在运行无关。
立即学习“Java免费学习笔记(深入)”;
- 假设主线程(非守护)启动一个守护线程后立即结束,JVM 立刻退出,守护线程会被强制中断
- 即使守护线程正在执行
sleep(10000)或 I/O 操作,JVM 也不会等待 - 守护线程中抛出的未捕获异常不会导致 JVM 崩溃,也不会阻止 JVM 退出
如何判断一个线程是否为守护线程
通过 isDaemon() 方法可查询当前线程状态:
-
System.out.println(Thread.currentThread().isDaemon());—— 主线程输出false - 子线程默认继承父线程的守护属性,即新线程默认是非守护线程
- 可通过
Thread.currentThread().setDaemon(true)在线程体内部尝试设置,但仅对新建线程有效(实际很少这么做)


















