守护线程与非守护线程

Q:守护线程不是应该是一种守护的存在嘛 就是保证程序不停止 为什么非守护线程才是这样

A:

非常好的问题!你指出了一个常见的理解误区。让我详细解释一下这个看似矛盾的现象。

关键理解:守护线程"守护"的对象不同

1. 守护线程的本质

java 复制代码
public class DaemonThreadDemo {
    public static void main(String[] args) {
        Thread daemonThread = new Thread(() -> {
            while (true) {
                System.out.println("守护线程在运行...");
                try { Thread.sleep(1000); } catch (InterruptedException e) {}
            }
        });
        
        daemonThread.setDaemon(true);  // 设置为守护线程
        daemonThread.start();
        
        System.out.println("主线程结束,程序立即退出(不会等待守护线程)");
    }
}
// 输出:
// 守护线程在运行...
// 主线程结束,程序立即退出(不会等待守护线程)
// 程序直接结束,守护线程被强制终止

2. 守护线程的真正含义

守护线程的"守护"意思是:

  • 守护的是JVM进程,而不是"守护程序不停止"
  • 当所有非守护线程结束时,JVM就会退出
  • JVM退出时,会强制终止所有还在运行的守护线程
  • 守护线程是为其他线程(非守护线程)服务的

3. 真实世界的类比

复制代码
医院急诊科场景:

非守护线程 = 急诊医生(必须工作到下班时间)
守护线程 = 保洁阿姨(医生下班了她也下班)

情况1:所有医生都下班了(非守护线程结束)
→ 保洁阿姨直接下班回家(守护线程被终止)
→ 急诊科关闭(JVM退出)

情况2:还有医生在值班(非守护线程存在)
→ 保洁阿姨继续工作(守护线程运行)
→ 急诊科保持开放(JVM运行)

4. Spring Boot中的实际线程分类

java 复制代码
public class SpringBootThreadAnalysis {
    public static void analyze() {
        // Spring Boot启动后典型的线程:
        
        // 非守护线程(保持JVM运行):
        // 1. Tomcat/Netty/Jetty的工作线程
        // 2. ScheduledExecutorService的核心线程
        // 3. 各种连接池的监控线程
        // 4. 消息监听线程
        
        // 守护线程(随JVM退出而终止):
        // 1. GC相关的后台线程
        // 2. JMX监控线程(部分)
        // 3. 某些后台清理线程
    }
}

5. 一个更具体的例子:Web服务器

java 复制代码
public class WebServerExample {
    public static void main(String[] args) {
        // 模拟Web服务器
        Thread serverThread = new Thread(() -> {
            System.out.println("Web服务器启动,监听8080端口...");
            while (true) {
                // 模拟处理请求
                try {
                    Thread.sleep(1000);
                    System.out.println("处理HTTP请求...");
                } catch (InterruptedException e) {
                    break;
                }
            }
        });
        
        // 关键决定:
        // 如果设置为守护线程:
        // serverThread.setDaemon(true);
        // main方法结束后,Web服务器线程立即被终止
        
        // 实际应该设置为非守护线程:
        serverThread.setDaemon(false); // 默认就是false
        serverThread.start();
        
        System.out.println("main方法执行完毕");
        // 但Web服务器线程是非守护线程,所以JVM继续运行
    }
}

6. 守护线程的典型用途

java 复制代码
public class DaemonThreadUseCases {
    public static void main(String[] args) {
        // 适合使用守护线程的场景:
        
        // 1. 垃圾回收监控(不关键)
        Thread gcMonitor = new Thread(() -> {
            while (true) {
                System.gc();
                try { Thread.sleep(60000); } catch (InterruptedException e) {}
            }
        });
        gcMonitor.setDaemon(true);  // 如果主程序结束,GC监控也不需要了
        
        // 2. 临时文件清理
        Thread tempCleaner = new Thread(() -> {
            while (true) {
                cleanTempFiles();
                try { Thread.sleep(3600000); } catch (InterruptedException e) {}
            }
        });
        tempCleaner.setDaemon(true);  // 程序结束,清理也终止
        
        // 3. 日志刷新(最后丢失一些日志可以接受)
        Thread logFlusher = new Thread(() -> {
            while (true) {
                flushLogs();
                try { Thread.sleep(5000); } catch (InterruptedException e) {}
            }
        });
        logFlusher.setDaemon(true);
        
        // 这些守护线程启动后
        // main线程做主要工作
        System.out.println("主程序开始工作...");
        // 主程序工作完成后退出
        // 所有守护线程自动终止
    }
}

7. Spring Boot中的实际配置

yaml 复制代码
# application.yml
server:
  tomcat:
    # 工作线程默认都是非守护的
    threads:
      max: 200
      min-spare: 10
java 复制代码
// Spring Boot创建线程池时的默认行为
@Bean
public ThreadPoolTaskExecutor taskExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(10);
    executor.setMaxPoolSize(50);
    executor.setThreadNamePrefix("async-");
    // 默认都是非守护线程,保证任务完成
    executor.setDaemon(false);  
    return executor;
}

总结澄清

常见的理解误区纠正:

错误理解 正确理解
守护线程是"守护程序不停止" 守护线程是"被守护"的,JVM退出时会被强制终止
需要守护线程来保持程序运行 需要非守护线程来保持程序运行
守护线程很重要,不能被终止 守护线程是辅助性的,可以随时被终止

记忆技巧:

  • 非守护线程 = 主人(JVM要等主人完成任务)
  • 守护线程 = 仆人(主人走了,仆人直接下班)
  • JVM只看还有没有**主人(非守护线程)**在工作

所以Spring Boot能持续运行,正是因为它创建了非守护线程(如Web服务器线程),这些线程告诉JVM:"我还没完事,你得等着"。而守护线程则像是临时工,主程序结束它们就自动被辞退了。

相关推荐
enjoy嚣士16 分钟前
springboot之Exel工具类
java·spring boot·后端·easyexcel·excel工具类
罗超驿27 分钟前
独立实现双向链表_LinkedList
java·数据结构·链表·linkedlist
盐水冰1 小时前
【烘焙坊项目】后端搭建(12) - 订单状态定时处理,来单提醒和顾客催单
java·后端·学习
凸头1 小时前
CompletableFuture 与 Future 对比与实战示例
java·开发语言
wuqingshun3141592 小时前
线程安全需要保证几个基本特征
java·开发语言·jvm
努力也学不会java2 小时前
【缓存算法】一篇文章带你彻底搞懂面试高频题LRU/LFU
java·数据结构·人工智能·算法·缓存·面试
攒了一袋星辰2 小时前
高并发强一致性顺序号生成系统 -- SequenceGenerator
java·数据库·mysql
小涛不学习2 小时前
Spring Boot 详解(从入门到原理)
java·spring boot·后端
于先生吖3 小时前
Java框架开发短剧漫剧系统:后台管理与接口开发
java·开发语言
daidaidaiyu4 小时前
Spring IOC 源码学习 声明式事务的入口点
java·spring