33

我正在自学 Java 线程,我注意到一些让我有点困惑的东西。我做了一个名为engineimplementation的类Runnable。run 方法只是打印“Hello World”,休眠一秒钟,然后重复。

在我的主要方法中,我有:

public static void main(String[] args) {
    Thread thread = new Thread(engine);
    thread.start();
    System.out.println("Done.");
}

正如我所料,我看到了“Hello World”和“Done”。打印的很快,说明main方法已经结束了,但没想到我开始的线程在main结束后还在运行。

为什么程序在 main 退出后仍继续执行?我原以为当 main 退出时,进程会终止,所有线程都会被强制清理。这是否意味着每个线程都必须显式地加入/终止 Java 程序才能终止?

4

6 回答 6

30

因为这就是它的工作原理。程序在被调用时退出System.exit(),或者在最后一个非守护线程停止运行时退出。

这是有道理的。例如,如果没有这个规则,每个只包含生成 GUI 的 Java 程序都必须无限等待()以避免程序立即退出。

于 2012-12-16T19:32:22.000 回答
28

如果您希望程序在 main 方法完成后退出,请考虑将您的线程设置为守护进程。但是请注意,当 main 完成时,守护线程将被中止。
你可以像这样创建一个守护进程thead:

Thread t = new Thread(...);
t.setDaemon(true);

所有非守护线程都是用户线程。这些线程正在阻止 jvm 关闭。

于 2012-12-16T19:32:15.667 回答
12

用户线程继续独立于其父线程(即创建者线程)的生命周期运行。因此,您必须在线程终止Thread.join之前通过调用显式加入线程。main

来自的JavadocThread

当 Java 虚拟机启动时,通常有一个非守护线程(通常调用某个指定类的名为 main 的方法)。Java 虚拟机继续执行线程,直到发生以下任一情况:

  1. 已调用 Runtime 类的退出方法,并且安全管理器已允许进行退出操作。

  2. 所有不是守护线程的线程都已经死亡,要么通过调用 run 方法返回,要么抛出传播到 run 方法之外的异常。

如果您希望 JVM 即使线程t正在运行也终止,您应该使线程t成为守护线程

t.setDaemon(true);
于 2012-12-16T19:28:48.150 回答
11

有两种类型的线程,用户和守护进程。当没有更多用户线程时,该进程终止。主线程始终是用户线程。您启动的线程也是用户线程,因此只要进程运行,它就会一直保持活动状态。

在你开始之前调用你的线程将使你的进程在你的函数返回时setDaemon(true)立即终止(或多或少) 。main()

于 2012-12-16T19:35:03.790 回答
7

Java 语言规范第 12.8 节指出:

12.8. 程序退出

当发生以下两种情况之一时,程序会终止其所有活动并退出:

所有不是守护线程的线程都会终止。

某些线程调用了Runtime类或System类的exit方法,安全管理器没有禁止exit操作。

这意味着主线程完成是不够的。

如果您确实希望它在主线程结束时退出,您需要使用Thread#setDaemon使新线程成为守护进程,或者按照最初的建议使用Thread#join 。

于 2012-12-16T19:37:04.430 回答
0

主线程也是一个正在创建的用户线程,它的生命周期类似于任何其他用户线程。
除非您将线程设置为守护线程,否则其他用户线程不依赖于主线程。一旦主线程完成其工作,它就会结束(它既不会结束其他用户线程,也不会因为其他用户线程正在运行而结束进程)。

于 2016-03-22T07:08:19.707 回答