JVM 终止时会发生啥?

Posted

技术标签:

【中文标题】JVM 终止时会发生啥?【英文标题】:What happens when the JVM is terminated?JVM 终止时会发生什么? 【发布时间】:2015-11-25 17:51:52 【问题描述】:

当 JVM 以 System.exit(0)^C 或类似的东西终止时会发生什么?我读过诸如“进程刚刚被吹走”和“每个线程都停止了”之类的东西,但我想知道究竟发生了什么。我已经知道shutdownHook 仍然会以某种方式被执行,但是在调用shutdownHooks 之前会发生什么以及在所有这些线程完成后会发生什么?

我想正确实现这样的shutdownHook,为此我需要对哪些仍然可以执行,哪些不会执行做出正确的假设。


更新:

一些代码:

class SomeObject 

    private boolean stopped;
    
    SomeObject() 
        stopped = false;
        Thread hook = new Thread() 

            @Override
            public void run() 
                stopped = true;
            

        ;
        hook.setPriority(Thread.MAX_PRIORITY);
        Runtime.getRuntime().addShutdownHook(hook);
    
    
    boolean map(Iterator<Object> it) 
        while(it.hasNext() && !stopped) 
            writeToOtherObject(it.next());
            it.remove();
        
        //have calculations finished?
        return !it.hasNext();
    

map 函数计算在其他对象中收集的结果。这个对象应该在一切都被分解之前存储在某个文件中(也可以通过普通优先级shutdownHooks)。这里的shutdownHook 有意义吗?据我了解,首先销毁所有线程,然后才运行shutdownHooks(同时,但我假设首先运行高优先级线程......),然后最终确定对象。这使得上面的代码相当无用,因为这个shutdownHook 的目的是确保在关闭已经开始时没有启动新的循环。我的理解是否正确和完整?

【问题讨论】:

这能回答你的问题吗? blog.joda.org/2014/02/exiting-jvm.html 您是否需要比Runtime.exit documentation 中的信息更多的信息?如果有,哪一部分不清楚? JVM什么时候终止?进程继续运行。 绝对不会发生的情况是线程被Thread.stop() 停止。它们就像被Thread.destroy() 停止一样。 @RealSkeptic 关闭顺序是我正在寻找的方向,但我也很好奇正在运行的线程会发生什么(如Marko Topolnik 所示)。我会用一个例子来更新我的问题 【参考方案1】:

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

最后一个非守护线程结束。 JVM 被中断(通过使用 ctrlC 或发送 SIGINT)。 JVM 被终止(通过发送 SIGTERM) 其中一个线程调用System.exit()Runtime.exit()

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

如果你中断了 JVM 或者系统向它发送了 TERM 信号,那么默认情况下,Shutdown.exit() 会被直接调用,而不需要与安全管理器进行检查。

Shutdown 类是java.lang 中的一个内部包私有类。除其他外,它还具有 exit()halt() 方法。它的exit() 方法做了一些事情来防止钩子被执行两次,等等,但基本上,它所做的是

    运行系统挂钩。系统挂钩由 JRE 方法在内部注册。它们按顺序运行,而不是在线程中运行。第二个系统挂钩运行您添加的应用程序挂钩。它将它们中的每一个都作为一个线程开始,然后在最后为它们中的每一个都有一个join。其他系统挂钩可能会在应用挂钩之前或之后运行。 如果终结器应该在停止之前运行,它们就会被运行。这通常甚至不应该发生,因为该方法已被弃用。如果退出的状态不是零,它无论如何都会忽略runFinalizersOnExit。 JVM 已停止。

现在,与您的假设相反,所有线程都在第 3 阶段停止。 halt 方法是本机的,我没有尝试阅读本机代码,但在调用它之前,唯一运行的代码是纯 Java,并且没有任何东西可以停止其中的线程。 documentation of Runtime.addShutdownHook 说,事实上:

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

(强调我的)

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

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

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

【讨论】:

这正是我需要知道的,非常感谢!对不起,我没有更仔细地选择有关优先级的词,我确实知道......【参考方案2】:

看看这个来自 DZone 的article。它详细介绍了 JVM 及其终止,重点是 ShutdownHook 的使用。

从高层次来看,它涵盖的一些重要假设包括:

    在某些情况下可能不会执行关闭挂钩! 一旦启动,Shutdown Hooks 可以在完成前强制停止。 您可以拥有多个 Shutdown Hook,但不能保证它们的执行顺序。 您无法在 Shutdown Hooks 中注册/取消注册 Shutdown Hooks 一旦关闭序列开始,它只能由 Runtime.halt() 停止。 使用关闭挂钩需要安全权限。 Shutdown Hooks 抛出的异常被视为与任何其他代码段抛出的异常相同。

【讨论】:

以上是关于JVM 终止时会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章

Android - 如果绑定活动被终止,绑定服务会发生啥?

工人 puma 日志提前终止是啥意思,为啥会发生?

JVM 如何终止守护线程?或如何编写优雅终止的守护线程

JVM如何终止守护程序线程?或者如何编写正常终止的守护程序线程

JVM垃圾回收篇(对象终止机制)

JVM垃圾回收篇(对象终止机制)