JVM终止后会发生什么?

Mr *_*der 16 java jvm shutdown

当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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Rea*_*tic 11

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

  • 最后一个非守护程序线程结束.
  • 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()方法做了一些事情来防止钩子被执行两次,等等,但基本上,它的作用是什么

  1. 运行系统挂钩.系统挂钩由JRE方法在内部注册.它们按顺序运行,而不是在线程中运行.第二个系统挂钩运行您添加的应用程序挂钩.它将每个作为一个线程启动,然后join在最后为每个线程创建一个.其他系统挂钩可以在应用程序挂钩之前或之后运行.
  2. 如果终结者应该在停止之前运行,那么它们就会被运行.这通常不会发生,因为该方法已被弃用.如果退出的状态不是零,则runFinalizersOnExit无论如何都会忽略它.
  3. JVM停止了.

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

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

(强调我的)

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

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

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