守护线程在jvm退出时被强制中止,不执行finally、close或shutdown钩子;仅非守护线程决定jvm存续;gc线程是典型守护线程;设置daemon属性须在线程new状态时完成。

JVM 退出时,守护线程不会被“通知”或“优雅终止”,而是直接停止执行——只要最后一个非守护线程结束,JVM 就立即调用 exit 流程,所有守护线程的执行被强制中止。
守护线程不参与 JVM 存活判定
Java 虚拟机只关心非守护线程(即用户线程)是否还在运行。一旦这些线程全部终止(包括正常结束、抛异常未捕获、或被 interrupt),JVM 就认定程序逻辑已完结,不再等待任何其他线程。
- 垃圾回收线程(GC Thread)是典型的守护线程,它在 main 线程退出后不会继续扫描堆内存
- 你手动创建的守护线程,哪怕正处在 Thread.sleep(60_000) 或写日志的 I/O 中,也会被瞬间切断
- JVM 不会触发其 finally 块、try-with-resources 的 close、也不会执行 Thread.UncaughtExceptionHandler
守护线程的销毁不是“退出”,而是“消失”
它没有 shutdown 过程,也没有回调机制。HotSpot 的实现方式是:遍历当前线程列表,若发现只剩守护线程,就跳过所有线程清理步骤,直接进入 VM exit 流程。
- 栈帧被直接回收,正在执行的方法中断,不返回、不抛出 InterruptedException
- 注册的 Runtime.addShutdownHook() 钩子必须是非守护线程,否则根本不会被调用
- 资源如文件句柄、Socket 连接、数据库连接等,若仅靠守护线程释放,大概率泄漏
设置时机决定能否成为真正的守护线程
守护属性只能在线程处于 NEW 状态时设置,start() 后再调用 setDaemon(true) 会抛 IllegalThreadStateException。
- 正确顺序:t.setDaemon(true); t.start();
- 主线程默认是非守护的,它创建的子线程也默认继承该状态
- Spring 的 @Async 默认使用 SimpleAsyncTaskExecutor,新建线程是非守护的;如需守护行为,须自定义 ThreadPoolTaskExecutor 并设 setDaemon(true)
适合与不适合的典型场景
判断标准很简单:这个任务是否允许“中途丢弃”?如果业务上必须保证执行完成,就不能交给守护线程。
- ✅ 适合:日志缓冲刷盘、JMX 心跳上报、定时监控指标采集、订单超时轮询
- ❌ 不适合:数据库连接池关闭、消息确认回执、文件上传完成回调、事务提交后清理










