Hi 大家好,我是 DHL,大厂程序员,公众号:ByteCode ,在美团、快手、小米工作过。搞过逆向,做过性能优化,研究过系统,擅长鸿蒙、Android、Kotlin、性能优化、职场分享。


主线程结束了,子线程是否可以正常运行

在面试交流群中,群友遇到了一个面试问题。

Q:主线程结束了,子线程是否可以正常运行?

在 Java 中,主线程结束后子线程是否继续运行取决于子线程的类型,线程分为守护线程(Daemon Thread)和用户线程(User Thread)。

用户线程(User Thread)

如果子线程是用户线程(User Thread)(即没有被设置为守护线程),用户线程则不依赖创建它的线程,那么当主线程结束时,子线程会继续运行,直到它们自然结束或被显式终止。

主线程与子线程是完全独立的生命周期,主线程的结束不会影响到子线程的执行状态。

以下是一个简单的例子,演示了用户线程在主线程结束后继续运行的情况:

public class MainThreadEndsExample {
    public static void main(String[] args) {
        Thread userThread = new Thread(() -> {
            try {
                for (int i = 0; i < 5; i++) {
                    System.out.println("用户线程运行: " + i);
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        userThread.start();

        try {
            Thread.sleep(2000); // 让子线程有时间运行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("主线程结束");
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.

在这个例子中,主线程在 2 秒后结束,用户线程仍然会继续运行直到完成它的任务

守护线程

守护线程的设计初衷是为了节省资源,通常用于执行一些后台任务,如垃圾回收、监控等。

可以通过 setDaemon(true) 方法,将线程设置为守护线程,但需要注意的是,设置守护线程必须在线程启动之前进行,否则会抛出 IllegalThreadStateException 异常。

如果子线程被设置为守护线程,那么当主线程结束时,如果 JVM 中,还有其他的用户线程,JVM 将等待这些用户线程结束,在这个过程中,守护线程将继续执行,直到所有用户线程结束,守护线程也会自动结束,JVM 也会退出。

以下是一个简单的例子,演示了守护线程和用户线程的行为:

public class DaemonThreadExample {

    public static void main(String[] args) {
        // 创建并启动一个守护线程
        Thread daemonThread = new Thread(() -> {
            System.out.println("守护线程启动");
            try {
                while (true) {
                    // 模拟后台任务
                    System.out.println("守护线程运行中");
                    Thread.sleep(1000); 
                }
            } catch (InterruptedException e) {
                System.out.println("守护线程被中断");
            }
        });
        daemonThread.setDaemon(true); // 设置为守护线程
        daemonThread.start();

        // 创建并启动一个用户线程
        Thread userThread = new Thread(() -> {
            System.out.println("用户线程启动");
            try {
                for (int i = 0; i < 5; i++) {
                    System.out.println("用户线程运行: " + i);
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                System.out.println("用户线程被中断");
            }
            System.out.println("用户线程结束");
        });
        userThread.start();

        // 主线程立即结束
        System.out.println("主线程结束");
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.

在这个例子中,尽管主线程很快结束,守护线程和用户线程都继续运行。用户线程在完成其任务后结束,随后守护线程也被中断和终止,JVM随之退出。这表明守护线程不会阻止JVM退出,它们会在所有用户线程结束后自动终止。

Q:主线程结束了,子线程是否可以正常运行

在 Java 中,默认情况下,主线程结束了,如果子线程是用户线程还会继续运行。

如果子线程都是守护线程,那么当主线程结束时,没有其它的用户线程,守护线程也会自动结束,JVM 也会退出。

但如果子线程中有用户线程,那么即使主线程结束了,用户线程仍会继续执行,直到所有的用户线程执行完毕,程序才会完全结束。


Hi 大家好,我是 DHL,大厂程序员,公众号:ByteCode ,在美团、快手、小米工作过。搞过逆向,做过性能优化,研究过系统,擅长鸿蒙、Android、Kotlin、性能优化、职场分享。