守护线程是为用户线程服务的后台线程,当所有非守护线程结束时,JVM立即终止守护线程并退出;其生命周期被动依赖于用户线程,不参与决定JVM存续,也不适合执行关键IO或事务操作。

Java 中守护线程并不与主程序“共存直到进程终止”,而是依赖于主程序(及其他非守护线程)的存活状态——它会在所有非守护线程结束时自动终止,而不是坚持运行到 JVM 退出那一刻。
换句话说:守护线程不是“和主程序一起活到最后一刻”,而是“主程序一走,它立刻停”。
守护线程的生命周期由 JVM 控制
JVM 是否继续运行,只看是否存在正在执行的非守护线程。
-
main线程默认是非守护线程; - 所有你显式
new Thread(...).start()创建的线程,默认也是非守护线程; - 只有调用了
thread.setDaemon(true)并且在start()之前设置的线程,才是守护线程; - 一旦 JVM 发现只剩守护线程还在跑,它会立即终止这些线程,并退出进程。
所以,守护线程本质上是“被动存活”:它不决定进程是否继续,而是被进程决定何时结束。
立即学习“Java免费学习笔记(深入)”;
主程序结束 ≠ 立刻退出?要看有没有其他非守护线程
常见误解:
“main 方法执行完,程序就结束了”
其实不然。JVM 会等待所有非守护线程执行完毕才退出。
比如:
public static void main(String[] args) {
Thread t = new Thread(() -> {
try { Thread.sleep(5000); }
catch (InterruptedException e) {}
System.out.println("子线程结束");
});
t.start(); // 非守护线程 → JVM 会等它完成
System.out.println("main 结束");
}输出:
main 结束 子线程结束
→ 这说明:即使 main 方法执行完了,只要还有非守护线程在跑,JVM 就不会退出。
而如果把 t.setDaemon(true) 加上,结果就是:
main 结束 (程序直接退出,子线程没机会打印)
如何让守护线程“看起来”和主程序共存?
实际开发中,常希望守护线程在主线程工作期间持续提供服务(如日志刷新、心跳上报、监控采样),这时只需确保:
- 守护线程在
main启动后开始运行; - 它不阻塞
main,也不持有必须显式释放的关键资源(如文件句柄、数据库连接); - 它的逻辑能响应中断(
Thread.interrupted()或检查isInterrupted()),便于测试或提前退出。
例如:
Thread monitor = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("监控中...");
try { Thread.sleep(2000); }
catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
});
monitor.setDaemon(true);
monitor.start();
// main 做点事,然后自然结束
Thread.sleep(6000);
System.out.println("main 退出 → JVM 即将关闭,monitor 自动终止");→ 这里 monitor 会运行约 6 秒(与 main 同步),但不会拖住 JVM;main 一结束,它就被 JVM 强制终止。
注意事项:守护线程不适合做关键任务
- ❌ 不要用于写入重要数据(如未 flush 的日志文件、未 commit 的事务);
- ❌ 不要用于持有外部资源(如 socket、数据库连接),因为 JVM 退出时不会给它清理机会;
- ✅ 适合轻量后台支持:定时打点、内存监控、GC 辅助、心跳维持等;
- ✅ 可以配合
Runtime.addShutdownHook()做最终清理(但注意:shutdown hook 是非守护线程,它本身也会被 JVM 等待执行完)。
不复杂但容易忽略:守护线程不是“延长进程寿命”的工具,而是“随业务线程退场”的辅助者。它的价值在于让后台服务无需手动管理生命周期,同时避免因遗漏 stop 导致 JVM 挂住。


















