且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

JVM终止后会发生什么?

更新时间:2023-11-09 23:04:46

让我们从可以启动关机序列的不同方式开始:

Let's begin from the different ways the shutdown sequence can be initiated:


  • 最后一个非守护程序线程结束。

  • JVM被中断(使用 ctrl C 或发送SIGINT)。

  • JVM终止(通过发送SIGTERM)

  • 其中一个线程调用 System.exit() Runtime.exit()

  • The last non-daemon thread ends.
  • The JVM is interrupted (by using ctrlC or sending SIGINT).
  • The JVM is terminated (by sending SIGTERM)
  • One of the threads calls System.exit() or Runtime.exit().

当调用 System.exit(int)时,它调用 Runtime.exit ()。它检查安全管理器是否允许以给定状态退出,如果是,则调用 Shutdown.exit()

When System.exit(int) is called, it calls Runtime.exit(). It checks with the security manager whether it is permitted to exit with the given status, and if so, calls Shutdown.exit().

如果你打断了JVM或系统发送了TERM信号,那么默认情况下,直接调用 Shutdown.exit()而不检查安全性经理。

If you interrupted the JVM or the system sent it the TERM signal, then by default, Shutdown.exit() is called directly without checking with the security manager.

Shutdown 类是 java中的内部包私有类。郎。除其他外,它有一个 exit()和一个 halt()方法。它的 exit()方法会做一些事情来防止钩子被执行两次,依此类推,但基本上,它的作用是

The Shutdown class is an internal, package-private class in java.lang. It has, among others, an exit() and a halt() methods. Its exit() method does some stuff to prevent the hooks from being executed twice, and so on, but basically, what it does is


  1. 运行系统挂钩。系统挂钩由JRE方法在内部注册。它们按顺序运行,而不是在线程中运行。第二个系统挂钩运行您添加的应用程序挂钩。它将每个作为一个线程启动,然后在最后为每个线程提供一个 join 。其他系统挂钩可以在应用程序挂钩之前或之后运行。

  2. 如果终结器应该在暂停之前运行,它们就会运行。这通常不会发生,因为该方法已被弃用。如果退出的状态为零,则无论如何都会忽略 runFinalizersOnExit

  3. JVM暂停。

  1. Run the System Hooks. The System Hooks are registered internally by JRE methods. They are ran sequentially, not in threads. The second system hook is what runs the application hooks that you have added. It starts each of them as a thread and then has a join for each of them at the end. Other system hooks may run before or after the application hooks.
  2. If finalizers are supposed to be ran prior to halting, they are ran. This should generally not even happen, as the method has been deprecated. And if the exit is with a status other than zero, it ignores the runFinalizersOnExit anyway.
  3. The JVM is halted.

现在,与您的假设相反,在第3阶段,所有线程都停止了。 halt 方法是原生的,我没有尝试读取本机代码,但是直到它被调用的那一刻,运行的唯一代码是纯Java,并且没有什么可以阻止其中任何地方的线程。 Runtime.addShutdownHook 实际上说:

Now, contrary to your supposition, it is at stage 3 that all the threads are stopped. The halt method is native, and I have not attempted to read the native code, but up to the moment it is called, the only code being ran is pure Java, and there is nothing that stops the threads anywhere in it. The documentation of Runtime.addShutdownHook says, in fact:


一个关机钩子只是一个初始化但未启动的线程。当虚拟机开始其关闭序列时,它将以某种未指定的顺序启动所有已注册的关闭挂钩,并让它们同时运行。当所有钩子都完成后,如果启用了终止退出,它将运行所有未被发送的终结器。最后,虚拟机将停止。 请注意,守护程序线程将在关闭序列期间继续运行,如果通过调用exit方法启动关闭,则非守护程序线程将继续运行。

(强调我的)

所以你看,确实告诉线程他们应该离开他们的循环确实是关闭钩子的工作的一部分

So you see, it is indeed part of the shutdown hook's job to tell threads that they should leave their loops and clean up.

你的另一个误解就是给线程一个高优先级。高优先级并不意味着线程将在所有其他挂钩之前首先运行。它只是意味着每当操作系统必须决定哪些线程处于准备运行状态以给CPU运行时,高优先级线程将具有更高的获胜概率 - 取决于关于操作系统的调度算法。简而言之,它可能会获得更多的CPU访问权限,但它不会 - 特别是如果你有多个CPU核心 - 必须在其他线程之前启动或在它们之前完成。

Another misconception you have is about giving the thread a high priority. A high priority doesn't mean that the thread will run first, before all other hooks. It merely means that whenever the operating system has to make a decision which of the threads which are in "ready to run" state to give to a CPU to run, a high-priority thread will have a higher probability of "winning" - depending on the operating system's scheduling algorithm. In short, it may get a little more CPU access, but it will not - especially if you have more than one CPU core - necessarily start before other threads or complete before them.

最后一件事 - 如果你想用一个标志告诉一个线程停止工作,那个标志应该是 volatile

One last thing - if you want to use a flag to tell a thread to stop working, that flag should be volatile.