Java并发编程:守护线程

开发 前端
Java程序在什么情况下会正常退出?当JVM中唯一运行的线程都是守护线程时,Java虚拟机才会退出。这句话源自JDK官方文档,即:当JVM中没有正在运行的非守护线程时,JVM进程会退出。

什么是守护线程?

与普通线程相比,守护线程(Daemon Thread)是一种特殊类型的线程。它的特殊性体现在哪里?在理解之前,我们需要先明确一个问题:

Java程序在什么情况下会正常退出?当JVM中唯一运行的线程都是守护线程时,Java虚拟机才会退出。这句话源自JDK官方文档,即:当JVM中没有正在运行的非守护线程时,JVM进程会退出。

直接理解可能有些抽象,但通过以下代码示例会更清晰:

public class Demo1 {
    public static void main(String[] args) throws InterruptedException {
        // 创建一个用户线程(非守护线程)
        Thread userThread = new Thread(() -> {
            // 无限循环
            while (true) {
                System.out.println("用户线程正在运行...");
                try {
                    Thread.sleep(2000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        userThread.start();

        Thread.sleep(1000);
        // 添加关闭钩子
        Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println("关闭钩子正在运行...")));
        System.out.println("主线程即将执行完毕");
    }
}

我们创建了一个用户线程,其逻辑是无限循环。运行这段代码后,猜猜主线程结束后,JVM进程会自动退出吗?

输出结果:

用户线程正在运行...
主线程即将执行完毕
用户线程正在运行...
用户线程正在运行...
用户线程正在运行...
用户线程正在运行...
...

可以看到,由于后台始终有一个非守护线程在运行,JVM无法正常自动退出,且关闭钩子(ShutdownHook)的逻辑也不会执行。程序会每隔2秒持续输出“用户线程正在运行...”。那么,如果是守护线程运行会怎样?

通过Thread.setDaemon(true)方法将线程设置为守护线程。代码如下:

public class Demo2 {
    public static void main(String[] args) throws InterruptedException {
        // 创建一个守护线程
        Thread thread = new Thread(() -> {
            // 无限循环
            while (true) {
                System.out.println("守护线程正在运行...");
                try {
                    Thread.sleep(2000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.setDaemon(true); // 设置为守护线程
        thread.start();

        Thread.sleep(1000);
        Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println("关闭钩子正在运行...")));
        System.out.println("主线程即将执行完毕");
    }
}

再次运行代码,观察结果:

输出结果:

守护线程正在运行...
主线程即将执行完毕
关闭钩子正在运行...

可以看到,当主线程退出时,JVM会直接退出,守护线程也随之终止。即使内部有无限循环,守护线程也会立即停止。

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

作用

Java引入守护线程的主要目的是提供一种机制来支持后台任务的执行。守护线程在程序生命周期中扮演辅助角色,为其他线程提供支持和服务。

以垃圾回收线程(GC)为例,它是一个经典的守护线程。当程序中不再有任何运行中的用户线程时,程序也不会再产生垃圾,垃圾回收线程也就无事可做。因此,当JVM中只剩下垃圾回收线程时,JVM会自动退出。GC始终在后台低优先级运行,实时监控和管理系统中的可回收资源。

使用场景

  1. 后台任务守护线程常用于执行与主线程无关的后台任务,例如日志记录、定时任务、监控等。这些任务可以默默在程序后台运行,不影响主流程。
  2. 垃圾回收垃圾回收是JVM的重要功能,负责回收无用对象并释放内存。垃圾回收线程是守护线程,会在程序运行时自动执行。
  3. 资源管理守护线程可用于资源管理,例如数据库连接池中的线程池管理器。它可以监控空闲连接,若连接长时间未使用,守护线程会自动关闭连接以避免资源浪费。
  4. 守护服务在服务器应用中,守护线程常用于提供服务。例如,Web服务器中的守护线程可以监听客户端请求。当所有客户端连接断开后,守护线程会自动关闭服务器。

注意事项守护线程的终止是不可控的。当程序中只剩下守护线程时,它会随主线程结束而自动终止。因此,使用守护线程时需确保任务可中断或可恢复,且不会影响程序的整体逻辑。

责任编辑:武晓燕 来源: 程序猿技术充电站
相关推荐

2011-12-29 13:31:15

Java

2025-02-19 00:05:18

Java并发编程

2025-01-10 07:10:00

2025-02-06 03:14:38

2024-12-31 09:00:12

Java线程状态

2019-11-07 09:20:29

Java线程操作系统

2023-10-08 09:34:11

Java编程

2025-02-03 08:23:33

2022-11-09 09:01:08

并发编程线程池

2023-10-18 15:19:56

2022-03-31 07:52:01

Java多线程并发

2019-09-16 08:45:53

并发编程通信

2025-02-03 00:40:00

线程组Java并发编程

2023-10-18 09:27:58

Java编程

2017-01-10 13:39:57

Python线程池进程池

2023-09-26 10:30:57

Linux编程

2017-09-19 14:53:37

Java并发编程并发代码设计

2021-05-06 08:11:03

Java用户线程守护线程

2020-09-04 10:29:47

Java线程池并发

2020-12-08 08:53:53

编程ThreadPoolE线程池
点赞
收藏

51CTO技术栈公众号