什么是守护线程?
与普通线程相比,守护线程(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始终在后台低优先级运行,实时监控和管理系统中的可回收资源。
使用场景
- 后台任务守护线程常用于执行与主线程无关的后台任务,例如日志记录、定时任务、监控等。这些任务可以默默在程序后台运行,不影响主流程。
- 垃圾回收垃圾回收是JVM的重要功能,负责回收无用对象并释放内存。垃圾回收线程是守护线程,会在程序运行时自动执行。
- 资源管理守护线程可用于资源管理,例如数据库连接池中的线程池管理器。它可以监控空闲连接,若连接长时间未使用,守护线程会自动关闭连接以避免资源浪费。
- 守护服务在服务器应用中,守护线程常用于提供服务。例如,Web服务器中的守护线程可以监听客户端请求。当所有客户端连接断开后,守护线程会自动关闭服务器。
注意事项守护线程的终止是不可控的。当程序中只剩下守护线程时,它会随主线程结束而自动终止。因此,使用守护线程时需确保任务可中断或可恢复,且不会影响程序的整体逻辑。