addShutdownHook 注册一个新的虚拟机的停止回调。
Java虚拟机遇到以下两种事件停止。
第一,程序正常退出,当最后一个非后台线程退出时,咖啡厅当System.exit方法被调用时。
第二, 当用户中断时,像 ^C,或者系统的事件,例如登出,或者系统关机。
关闭回调是一个只初始化,但并没有启动的线程。当虚拟机开始它的关闭步骤时,它会启动所有注册的关闭回调,这些回调以不确定次序的并发的方式运行。 当所有的回调结果后,如果启用了关闭时终结,那么会运行所有未调用的终结器。 最终,虚拟机会停止。 注意,后台线程在关闭过程中会继续运行。
一旦关闭过程已经启动,只能通过调用halt来结束,它会强迫终止虚拟机。
一旦关闭过程已经启动,不能注册新的关闭回调,也不能取消注册之前已经注册的回调。尝试任何一个操作会导致抛出 IllegalStateException.
关闭回调运行在虚拟机生命周期的一个微妙的时刻,应该编码时保守一些。 特别的,写成线程安全的方式,尽量避免出现死锁。 它现不应该盲目依赖自身已经注册关闭回调的服务,这些服务可能处于关闭的过程中。尝试使用其它的基于线程的服务,像AWT事件分发线程,可能导致死锁。
关闭回调应该快速结束它的工作。 当程序调用exit时,会期望虚拟机尽快结束。 当用户登出系统时,或者系统关闭时,底层的操作系统可能只允许一个固定的时间来关闭退出。 因此,尝试任何用户交互,或者在关闭回调时进行长时间计算是不明智的。
在关闭回调中,未捕获异常像其它的线程异常一样处理。通过调用线程的ThreadGroup.uncaughtException方法。这个方法的默认实现是把异常的栈信息打印到标准错误输出里,然后终止线程。它不会导致虚拟机退出。
在很少的情况下,虚拟机可能直接退出,即没有干净的关闭就停止运行。 在虚拟机被外部关闭时会发生,如在Unix系统中发出一个SIGKILL信号,或者 在Windows上调用TerminateProcess。 如果原生方法出现错误虚拟机也会直接停止,如内部数据结构损坏,或者 尝试访问不存在的内存。 如果虚拟机直接停止,那么不保证关闭回调会被运行。
/**
* Registers a new virtual-machine shutdown hook.
*
* <p> The Java virtual machine <i>shuts down</i> in response to two kinds
* of events:
*
* <ul>
*
* <li> The program <i>exits</i> normally, when the last non-daemon
* thread exits or when the <tt>{@link #exit exit}</tt> (equivalently,
* {@link System#exit(int) System.exit}) method is invoked, or
*
* <li> The virtual machine is <i>terminated</i> in response to a
* user interrupt, such as typing <tt>^C</tt>, or a system-wide event,
* such as user logoff or system shutdown.
*
* </ul>
*
* <p> A <i>shutdown hook</i> is simply an initialized but unstarted
* thread. When the virtual machine begins its shutdown sequence it will
* start all registered shutdown hooks in some unspecified order and let
* them run concurrently. When all the hooks have finished it will then
* run all uninvoked finalizers if finalization-on-exit has been enabled.
* Finally, the virtual machine will halt. Note that daemon threads will
* continue to run during the shutdown sequence, as will non-daemon threads
* if shutdown was initiated by invoking the <tt>{@link #exit exit}</tt>
* method.
*
* <p> Once the shutdown sequence has begun it can be stopped only by
* invoking the <tt>{@link #halt halt}</tt> method, which forcibly
* terminates the virtual machine.
*
* <p> Once the shutdown sequence has begun it is impossible to register a
* new shutdown hook or de-register a previously-registered hook.
* Attempting either of these operations will cause an
* <tt>{@link IllegalStateException}</tt> to be thrown.
*
* <p> Shutdown hooks run at a delicate time in the life cycle of a virtual
* machine and should therefore be coded defensively. They should, in
* particular, be written to be thread-safe and to avoid deadlocks insofar
* as possible. They should also not rely blindly upon services that may
* have registered their own shutdown hooks and therefore may themselves in
* the process of shutting down. Attempts to use other thread-based
* services such as the AWT event-dispatch thread, for example, may lead to
* deadlocks.
*
* <p> Shutdown hooks should also finish their work quickly. When a
* program invokes <tt>{@link #exit exit}</tt> the expectation is
* that the virtual machine will promptly shut down and exit. When the
* virtual machine is terminated due to user logoff or system shutdown the
* underlying operating system may only allow a fixed amount of time in
* which to shut down and exit. It is therefore inadvisable to attempt any
* user interaction or to perform a long-running computation in a shutdown
* hook.
*
* <p> Uncaught exceptions are handled in shutdown hooks just as in any
* other thread, by invoking the <tt>{@link ThreadGroup#uncaughtException
* uncaughtException}</tt> method of the thread's <tt>{@link
* ThreadGroup}</tt> object. The default implementation of this method
* prints the exception's stack trace to <tt>{@link System#err}</tt> and
* terminates the thread; it does not cause the virtual machine to exit or
* halt.
*
* <p> In rare circumstances the virtual machine may <i>abort</i>, that is,
* stop running without shutting down cleanly. This occurs when the
* virtual machine is terminated externally, for example with the
* <tt>SIGKILL</tt> signal on Unix or the <tt>TerminateProcess</tt> call on
* Microsoft Windows. The virtual machine may also abort if a native
* method goes awry by, for example, corrupting internal data structures or
* attempting to access nonexistent memory. If the virtual machine aborts
* then no guarantee can be made about whether or not any shutdown hooks
* will be run. <p>
*
* @param hook
* An initialized but unstarted <tt>{@link Thread}</tt> object
*
* @throws IllegalArgumentException
* If the specified hook has already been registered,
* or if it can be determined that the hook is already running or
* has already been run
*
* @throws IllegalStateException
* If the virtual machine is already in the process
* of shutting down
*
* @throws SecurityException
* If a security manager is present and it denies
* <tt>{@link RuntimePermission}("shutdownHooks")</tt>
*
* @see #removeShutdownHook
* @see #halt(int)
* @see #exit(int)
* @since 1.3
*/
public void addShutdownHook(Thread hook) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("shutdownHooks"));
}
ApplicationShutdownHooks.add(hook);
}