当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
函数计算在其他对象中收集的结果。在所有内容都被分解之前,该对象应存储在某个文件中(通过普通优先级shutdownHook
也是如此)。 shutdownHook
这里有意义吗?据我所知,所有线程首先被销毁,然后才运行shutdownHook
(同时,但我假设首先运行高优先级线程......)然后最终确定对象。这使得上面的代码相当无用,因为这个shutdownHook
的意图是确保在关闭已经开始时没有启动新的循环。我的理解是否正确和完整?
答案 0 :(得分:10)
让我们从可以启动关机序列的不同方式开始:
System.exit()
或Runtime.exit()
。调用System.exit(int)
时,会调用Runtime.exit()
。它会检查安全管理器是否允许以给定状态退出,如果是,则调用Shutdown.exit()
。
如果您中断了JVM或系统向其发送了TERM信号,则默认情况下会直接调用Shutdown.exit()
而不检查安全管理器。
Shutdown
类是java.lang
中的内部包私有类。除其他外,它还包含exit()
和halt()
方法。它的exit()
方法做了一些事情来防止钩子被执行两次,依此类推,但基本上它做的是
join
。其他系统挂钩可以在应用程序挂钩之前或之后运行。runFinalizersOnExit
。现在,与您的假设相反,在第3阶段,所有线程都停止了。 halt
方法是本机方法,我没有尝试读取本机代码,但是直到它被调用的那一刻,运行的唯一代码是纯Java,并且没有任何东西可以阻止其中的任何地方的线程。实际上documentation of Runtime.addShutdownHook
说:
关闭钩子只是一个初始化但未启动的线程。当虚拟机开始其关闭序列时,它将以某种未指定的顺序启动所有已注册的关闭挂钩,并让它们同时运行。当所有挂钩都完成后,如果启用了finalization-on-exit,它将运行所有未读取的终结器。最后,虚拟机将停止。 请注意,守护程序线程将在关闭序列期间继续运行,如果通过调用exit方法启动关闭,则非守护程序线程将继续运行。
(强调我的)
所以你看,确实告诉线程他们应该离开他们的循环并进行清理,这确实是shutdown hook工作的一部分。
你的另一个误解是关于给予线程高优先级。高优先级并不意味着线程将在所有其他挂钩之前首先运行。它只是意味着每当操作系统必须决定哪些线程准备好运行时#34;为了让CPU运行,一个高优先级的线程将有更高的概率赢得&#34; - 取决于操作系统的调度算法。简而言之,它可能会获得更多的CPU访问权限,但它不会 - 特别是如果你有多个CPU核心 - 必须在其他线程之前启动或在它们之前完成。
最后一件事 - 如果你想用一个标志告诉一个线程停止工作,那个标志应该是volatile
。
答案 1 :(得分:3)
从DZone看一下这个article。它详细介绍了JVM及其终止,重点关注ShutdownHook
的使用。
从较高层面来看,它涵盖的一些重要假设包括:
- 在某些情况下可能无法执行关机挂钩!
- 启动后,可以在完成前强制停止关机挂钩。
- 您可以拥有多个Shutdown Hook,但无法保证其执行顺序。
- 您无法在关机挂钩中注册/取消注册关机挂钩
- 一旦关闭序列启动,它只能由Runtime.halt()停止。
- 使用关机挂钩需要安全权限。
- Shutdown Hooks抛出的异常与任何其他代码段抛出的异常一样。
醇>