守护线程是jvm退出时不会阻止进程终止的线程,所有非守护线程结束后jvm立即退出,其典型代表是垃圾回收线程;必须在start()前设置setdaemon(true),且状态不可逆,不可用于关键清理任务。

守护线程是什么:一个“随 JVM 一起消失”的线程
守护线程(Daemon Thread)不是后台服务,也不是高级线程类型——它只是 JVM 关机时不会阻止退出的线程。只要所有非守护线程结束,JVM 就立刻终止,不管守护线程是否还在跑。
典型例子:GarbageCollector 线程就是守护线程;你写的 main 方法启动的主线程默认是非守护的。
-
Thread.setDaemon(true)必须在start()之前调用,否则抛IllegalThreadStateException - 守护线程创建的子线程默认继承其守护状态(即也是守护线程)
- 守护线程里不能做关键清理工作(比如写日志、关数据库连接),因为可能被突然中断
怎么判断一个线程是不是守护线程
直接查 isDaemon() 返回值就行,别靠名字或逻辑猜:
Thread t = new Thread(() -> { /* ... */ });
System.out.println(t.isDaemon()); // false —— 新线程默认非守护
t.setDaemon(true);
System.out.println(t.isDaemon()); // true-
main线程永远是非守护的,哪怕你在 main 里调了setDaemon(true)(无效,会抛异常) - 守护状态不可逆:设成
true后不能改回false - 注意 IDE 调试时可能看到多个守护线程(如
Monitor Ctrl-Break),它们是工具线程,不影响你的逻辑
垃圾回收线程为什么必须是守护线程
GC 线程本质是 JVM 内部调度的辅助线程,它的存在只为服务用户线程。一旦所有用户线程结束,JVM 没有继续运行的理由,GC 也就失去意义。
立即学习“Java免费学习笔记(深入)”;
- 如果 GC 是非守护线程,JVM 就得等它“自己停下来”,但 GC 没有明确退出点,会导致进程卡住不退出
- 不同 JVM 实现(HotSpot / OpenJ9)的 GC 线程名不同,但都标记为 daemon,可通过
jstack <pid></pid>验证 - 你无法手动启动或控制 GC 线程;调用
System.gc()只是建议,不创建新线程
常见误用:把定时任务、日志刷盘线程设成守护线程
这类线程看起来“后台运行”,但实际承担关键职责——设成守护线程后,主流程一结束,它们就被粗暴中断,数据可能丢失。
- Spring 的
@Scheduled默认使用非守护线程池;若手动配ScheduledThreadPoolExecutor,需确认threadFactory没设daemon=true - Log4j2 的异步日志器(
AsyncLogger)内部线程是守护的,但它自带缓冲和优雅关闭机制;自研类似逻辑时千万别照搬 - 用
Runtime.addShutdownHook()注册的钩子线程本身是非守护的,且 JVM 保证它执行完才退出——这才是做清理的正地方
守护线程的边界很窄:只适合纯辅助、无状态、可随时丢弃的任务。多数业务场景里,宁可多花几毫秒等它做完,也不要赌它“刚好跑完了”。









