http://blog.csdn.net/tiwerbao/article/details/8933147
Runtime.getRuntime().addShutdownHook(new MyShutdownHook());
http://blog.csdn.net/tiwerbao/article/details/8933157
主要通过java.lang.Shutdown和java.lang.ApplicationShutdownHooks 这两个工具类来实现。Shutdown负责触发钩子,而ApplicationShutdownHooks负责维护钩子。
Shutdown
Runtime.getRuntime().addShutdownHook(new MyShutdownHook());
http://blog.csdn.net/tiwerbao/article/details/8933157
主要通过java.lang.Shutdown和java.lang.ApplicationShutdownHooks 这两个工具类来实现。Shutdown负责触发钩子,而ApplicationShutdownHooks负责维护钩子。
Shutdown
- private static final int RUNNING = 0;
- private static final int HOOKS = 1;
- private static final int FINALIZERS = 2;
- private static int state = RUNNING;
- private static final int MAX_SYSTEM_HOOKS = 10;
- private static final Runnable[] hooks = new Runnable[MAX_SYSTEM_HOOKS];
A Runtime.exit(),这时候会调用Shutdown.exit();
B JNI来DestroyJVM,这时候会调用Shutdown.shutdown();
这两个方法,最后都会调用Shutdown.sequence()来触发关闭钩子和停止JVM。
- private static void sequence() {
- synchronized (lock) {
- if (state != HOOKS) return;
- }
- runHooks(); // 执行关闭钩子
- boolean rfoe;
- synchronized (lock) {
- state = FINALIZERS;
- rfoe = runFinalizersOnExit;
- }
- if (rfoe) runAllFinalizers(); // 全面停止系统
- }
- private static void runHooks() {
- for (int i=0; i < MAX_SYSTEM_HOOKS; i++) {
- try {
- Runnable hook;
- synchronized (lock) {
- currentRunningHook = i;
- hook = hooks[i];
- }
- if (hook != null) hook.run();
- } catch(Throwable t) {}
- }
- }
java.lang.ApplicationShutdownHooks
用户等级的关闭钩子由ApplicationShutdownHooks来存放和维护。
在ApplicationShutdownHooks中,通过一个Map属性hooks来保存用户的关闭钩子。实际上每个关闭钩子都是一个线程,当JVM关闭事件触发的时候,就会执行钩子逻辑。
- private staticIdentityHashMap<Thread, Thread> hooks;
在ApplicationShutdownHooks加载的时候,首先会往Shutdown中add一个应用类型(1)的钩子类型线程,然后把 执行钩子逻辑的runHooks() 放入run()中等待调用。
这里ApplicationShutdownHooks为什么不实现Runnable接口,然后直接把自己add到Shutdown中呢? 因为没有必要:
因为Shutdown只关心用户的钩子,而对维护者ApplicationShutdownHooks没有兴趣,基于安全或者使用来考虑,都没有必要把ApplicationShutdownHooks整个传进去。所以这里新建一个线程,只把 runHooks()的调用 放进去,足矣。
这样一来,ApplicationShutdownHooks就不用实例化,可以做成单例,彻底变成了一个工具类,只用适度地暴露一些工具方法即可,并且通过静态属性hooks来保存钩子。
class ApplicationShutdownHooks {
/* The set of registered hooks */
private static IdentityHashMap<Thread, Thread> hooks;
static {
try {
Shutdown.add(1 /* shutdown hook invocation order */,
false /* not registered if shutdown in progress */,
new Runnable() {
public void run() {
runHooks();
}
}
);
hooks = new IdentityHashMap<>();
} catch (IllegalStateException e) {
// application shutdown hooks cannot be added if
// shutdown is in progress.
hooks = null;
}
}
private ApplicationShutdownHooks() {}
/* Iterates over all application hooks creating a new thread for each
* to run in. Hooks are run concurrently and this method waits for
* them to finish.
*/
static void runHooks() {
Collection<Thread> threads;
synchronized(ApplicationShutdownHooks.class) {
threads = hooks.keySet();
hooks = null;
}
for (Thread hook : threads) {
hook.start();
}
for (Thread hook : threads) {
try {
hook.join();
} catch (InterruptedException x) { }
}
}