Java 中的线程分为两类,守护线程和非守护线程,非守护线程也称用户线程,我们默认开的线程一般都是非守护线程。

守护线程是一些比较特殊线程,通常处理一些后台支持性的工作,如垃圾回收线程。

在正常启动一个普通线程的时候,当这个线程一直处于运行状态,JVM 并不会退出,如下示例是开启一个无线循环的线程,当这个线程启动后,如果不手动停止 JVM,那么就会一直执行下去。

Java 中规定,如果所有非守护线程退出后,JVM 进程将会退出,因此守护线程不会影响 JVM 的退出,也就是说当 JVM 线程结束时,守护线程会自动关闭,这就免去了继续关闭线程的麻烦。

由于守护线程具备这种自动结束生命周期的特性,因此当 JVM 进程退出而一些线程需要自动关闭的时候,则可以将其设置为守护线程。

Java 8 中 Completablefuture 的 async 方法默认的用的线程就是守护线程,而普通的线程池用的是用户线程,选择使用时应该注意。

守护线程、用户线程、JVM 运行关系如下图:

将一个线程设置为守护线程是通过 thread.setDaemon(true) 方法,这个操作必须在调用开启线程 start() 方法前,否则会抛异常

可以看到当把线程设置为守护线程后,运行结果就完全不同了,随着 main 函数的结束,JVM 退出,该线程也随之结束,因此守护线程可以认为守护的是 JVM。

public static void main(String[] args) {
    Runnable runnable = () -> {
        while (true){
            System.out.println("线程在工作");
        }

    };
    Thread thread = new Thread(runnable);
      //设置为守护线程
    thread.setDaemon(true);
    thread.start();
    System.out.println("启动线程成功");
}

如果在守护线程中,再开启一个线程执行,这个线程是否是守护呢

可以看到主函数退出后线程也随即退出了,因此在守护线程中开启的线程默认都是守护线程

public static void main(String[] args) {
        Runnable runnable = () -> {
            //线程中又开启了一个线程
            Runnable runnable1 = () -> {
                while (true){
                    System.out.println("线程在工作");
                }
            };
            Thread thread = new Thread(runnable1);
            thread.start();
        };
        Thread thread = new Thread(runnable);
        thread.setDaemon(true);
        thread.start();
        System.out.println("启动线程成功");
    }
}