基于本文回答

播面 播面

文图音视,全方位拆解八股文
0
评论

Java中守护线程(Daemon Thread)和用户线程有什么区别?

知识点图片

在 Java 中,线程被分为两类:用户线程(User Thread)守护线程(Daemon Thread)

它们之间最核心的区别在于:它们对 JVM(Java 虚拟机)的退出机制影响不同。

以下是详细的区别和解析:

1. 核心区别:对 JVM 退出的影响

  • 用户线程:JVM 会等待所有的用户线程执行完毕后才退出。只要还有一个用户线程在运行,JVM 就不会终止。
  • 守护线程:JVM 不会等待守护线程执行完毕。当所有用户线程都结束时,JVM 会自动退出,并且会强行终止所有正在运行的守护线程。

2. 角色与作用

  • 用户线程:通常用于执行应用程序的核心业务逻辑。比如我们平时通过 new Thread() 创建的线程,或者 main 方法所在的线程,默认都是用户线程。
  • 守护线程:通常用于在后台为其他线程(用户线程)提供服务或支持。最经典的例子就是垃圾回收线程(GC Thread)。 当没有用户线程运行时,垃圾回收也没有意义了,所以 JVM 会直接退出。

3. 如何创建守护线程

在 Java 中,创建的线程默认是用户线程。如果要将其变为守护线程,必须在调用 start() 方法之前,调用 setDaemon(true) 方法。

java
Thread thread = new Thread(() -> {
    while (true) {
        System.out.println("守护线程正在运行...");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
});

// 将线程设置为守护线程(必须在 start() 之前调用)
thread.setDaemon(true); 
thread.start();

4. 代码演示对比

看看下面这段代码,体会守护线程和用户线程的区别:

java
public class DaemonThreadDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread daemonThread = new Thread(() -> {
            while (true) {
                System.out.println("后台守护线程在执行...");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        // 如果注释掉下面这行,daemonThread 就是用户线程,程序会一直死循环运行下去。
        // 如果保留这行,daemonThread 是守护线程,当 main 线程结束后,程序很快就会自动停止。
        daemonThread.setDaemon(true); 
        
        daemonThread.start();

        System.out.println("Main 线程(用户线程)开始执行...");
        Thread.sleep(2000); // 模拟主线程工作 2 秒
        System.out.println("Main 线程(用户线程)执行结束!");
    }
}

5. 使用守护线程的注意事项(重要)

  1. 设置时机thread.setDaemon(true) 必须在 thread.start() 之前设置,否则会抛出 IllegalThreadStateException 异常。
  2. 继承性:在守护线程中创建的新线程,默认也是守护线程;在用户线程中创建的线程,默认是用户线程。
  3. 不要在守护线程中执行 I/O 操作或写数据库:这是非常危险的。因为当所有的用户线程结束后,JVM 会立即关闭,守护线程会被瞬间强行中断。此时,守护线程中的 finally可能根本不会执行,这会导致文件流没有关闭、数据库连接未释放或数据写到一半损坏的情况。

总结表格

比较维度 用户线程 (User Thread) 守护线程 (Daemon Thread)
存在目的 执行程序核心业务逻辑 在后台为用户线程提供服务/支持
JVM 退出 JVM 会等待所有用户线程结束才退出 JVM 不等待,一旦无用户线程,直接强行退出
默认状态 main 线程及新创建的线程默认都是此类型 需要显式调用 setDaemon(true) 设置
典型代表 Main 线程 垃圾回收器 (GC) 线程
适用场景 业务处理、数据计算等 内存清理、心跳检测、后台日志清理等
00:00
00:00