• Java并发-为什么主线程结束了,程序却没有关闭呢?


    守护线程与用户线程的定义及区别

    Java 中的线程分为两类,分别为 daemon 线程(守护线程)和 user 线程(用户线程)。

    在 JVM 启动时会调用 main 函数, main 函数所在的线程就是一个用户线程,其实在 JVM 内部同时还启动了好多守护线程,比如垃圾回收线程。

    守护线程定义:当所有的非守护线程结束时,程序也就终止了,同时会杀死进程中的所有守护线程。反过来说,只要任何非守护线程还在运行,程序就不会终止

    用户线程定义:某种意义上的主要用户线程,只要有用户线程未执行完毕,JVM 虚拟机不会退出

    main函数所在线程是一个用户线程,我们自己创建的线程也是一个用户线程。即使主线程结束了,其他用户线程还没有结束,Java程序也不会结束。

     守护线程

    Java 中的守护线程和 Linux 中的守护进程是有些区别的,Linux 守护进程是系统级别的,当系统退出时,才会终止。

    Java 中的守护线程是 JVM 级别的,当 JVM 中无任何用户进程时,守护进程销毁,JVM 退出,程序终止。总结来说,Java 守护进程的最主要的特点有:

    • 守护线程是运行在程序后台的线程
    • 守护线程创建的线程,依然是守护线程
    • 守护线程不会影响 JVM 的退出,当 JVM 只剩余守护线程时,JVM 进行退出;
    • 守护线程在 JVM 退出时,自动销毁
    • 守护线程应该永远不去访问固有资源,如文件、数据库,因为它会在任何时候甚至在一个操作的中间发生中断。

    创建方式:将线程转换为守护线程可以通过调用 Thread 对象的 setDaemon (true) 方法来实现。

    守护线程与 JVM 的退出实验

    方案一

    • 创建 1 个线程,线程名为 threadOne;
    • run 方法线程 sleep 1000 毫秒后,进行求和计算,求解 1 + 2 + 3 + … + 100 的值;
    • 将线程 threadOne 设置为守护线程;
    • 执行代码,最终打印的结果;

    方案二

    • 在方案一基础上加入 join 方法,强制让用户线程等待守护线程 threadOne;
    • 执行代码,最终打印的结果。

    方案一结果

    方法二结果

     

    【分析】方法一产生的结果是因为,主线程(用户线程)执行完毕,JVM直接将守护线程销毁了。

    【分析】方法二产生结果,是因为主线程等待守护线程执行完毕后才结束。

    1. public class DaemonTest {
    2. public static void main(String[] args) throws InterruptedException {
    3. Thread daemon = new Thread(()->{
    4. try {
    5. Thread.sleep(1000);
    6. int sum = 0;
    7. for (int i = 0; i < 100; i++) {
    8. sum += i;
    9. }
    10. System.out.println(sum);
    11. } catch (InterruptedException e) {
    12. e.printStackTrace();
    13. }
    14. });
    15. // 设置守护线程
    16. daemon.setDaemon(true);
    17. daemon.start();
    18. // daemon.join();
    19. System.out.println("主线程结束");
    20. }
    21. }

    守护线程的作用及使用场景

    作用:我们以 GC 垃圾回收线程举例,它就是一个经典的守护线程,当我们的程序中不再有任何运行的 Thread, 程序就不会再产生垃圾,垃圾回收器也就无事可做,所以当垃圾回收线程是 JVM 上仅剩的线程时,垃圾回收线程会自动离开。

    应用场景

    • 为其它线程提供服务支持的情况,可选用守护线程;
    • 根据开发需求,程序结束时,这个线程必须正常且立刻关闭,就可以作为守护线程来使用;
    • 如果一个正在执行某个操作的线程必须要执行完毕后再释放,否则就会出现不良的后果的话,那么这个线程就不能是守护线程,而是用户线程;
    • 正常开发过程中,一般心跳监听,垃圾回收,临时数据清理等通用服务会选择守护线程
  • 相关阅读:
    如何进行数据库的迁移与同步——【DBA 从入门到实践】第四期
    java 搜索指定文件夹下指定字符串并将其写入 txt 文件中
    SpringBoot整合Dubbo
    Brain Teaser概率类 - 抛硬币
    TX12 + ExpressLRS 915MHz RC控制链路配置及问题汇总
    KubeSphere安装KubeEdge
    KMP算法详解,3000字详解,带你学会next数组
    【c++】Lambda表达式
    EN 13241工业、商业、车库门和大门—CE认证
    独立站FP收款黑科技来啦!再也不用担心账户被封了~
  • 原文地址:https://blog.csdn.net/abc123mma/article/details/128049412