赞
踩
Runtime.getRuntime().addShutdownHook(new Thread(){
@Override
public void run() {
System.out.println("I'm shutdown hook...");
}
});
// org.apache.rocketmq.broker.BrokerStartup#createBrokerController public static BrokerController createBrokerController(String[] args) { ... Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { private volatile boolean hasShutdown = false; private AtomicInteger shutdownTimes = new AtomicInteger(0); @Override public void run() { synchronized (this) { log.info("Shutdown hook was invoked, {}", this.shutdownTimes.incrementAndGet()); if (!this.hasShutdown) { this.hasShutdown = true; long beginTime = System.currentTimeMillis(); controller.shutdown(); long consumingTimeTotal = System.currentTimeMillis() - beginTime; log.info("Shutdown hook over, consuming total time(ms): {}", consumingTimeTotal); } } } }, "ShutdownHook")); }
1、当我们添加一个ShutdownHook时,会调用ApplicationShutdownHooks.add(hook),往ApplicationShutdownHooks类下的静态变量private static IdentityHashMap<Thread, Thread> hooks添加一个hook,hook本身是一个thread对象
2、ApplicationShutdownHooks类初始化时会把hooks添加到Shutdown的hooks中去
// java.lang.ApplicationShutdownHooks 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; } }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GuVH9T7Y-1675508025694)(evernotecid://4143277E-C9B7-4F5C-948C-63A95AD76A67/appyinxiangcom/20976546/ENNote/p880?hash=b01f3a2b036137a6231593be6ad05a5a)]
系统Shutdown仅仅支持10个slot
系统设定 slot=1为应用注册的hook
// java.lang.Shutdown
// The system shutdown hooks are registered with a predefined slot.
// The list of shutdown hooks is as follows:
// (0) Console restore hook
// (1) Application hooks
// (2) DeleteOnExit hook
private static final int MAX_SYSTEM_HOOKS = 10;
顺序遍历每个slot,并发执行每个slot里面注册的hooks
private static IdentityHashMap<Thread, Thread> hooks;
// java.lang.Shutdown#runHooks private static void runHooks() { for (int i=0; i < MAX_SYSTEM_HOOKS; i++) { try { Runnable hook; synchronized (lock) { // acquire the lock to make sure the hook registered during // shutdown is visible here. currentRunningHook = i; hook = hooks[i]; } if (hook != null) hook.run(); } catch(Throwable t) { if (t instanceof ThreadDeath) { ThreadDeath td = (ThreadDeath)t; throw td; } } } }
并发执行每个slot里面注册的hooks
// java.lang.ApplicationShutdownHooks#runHooks static void runHooks() { Collection<Thread> threads; synchronized(ApplicationShutdownHooks.class) { threads = hooks.keySet(); hooks = null; } for (Thread hook : threads) { hook.start(); } for (Thread hook : threads) { while (true) { try { hook.join(); break; } catch (InterruptedException ignored) { } } } }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KNbaoL51-1675508025695)(evernotecid://4143277E-C9B7-4F5C-948C-63A95AD76A67/appyinxiangcom/20976546/ENNote/p880?hash=bbef4e2bbd683b4ecd011a9c04e4ca08)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4CWxD8IE-1675508025695)(evernotecid://4143277E-C9B7-4F5C-948C-63A95AD76A67/appyinxiangcom/20976546/ENNote/p880?hash=c960431444d0027391dd6a911d14b6f3)]
Shutdown.exit的调用方,发现有 Runtime.exit 和 Terminator.setup
// java.lang.Terminator static void setup() { if (handler == null) { SignalHandler var0 = new SignalHandler() { public void handle(Signal var1) { Shutdown.exit(var1.getNumber() + 128); } }; handler = var0; try { Signal.handle(new Signal("HUP"), var0); } catch (IllegalArgumentException var4) { } try { Signal.handle(new Signal("INT"), var0); } catch (IllegalArgumentException var3) { } try { Signal.handle(new Signal("TERM"), var0); } catch (IllegalArgumentException var2) { } } }
该方法会在最后一个非daemon线程(非守护线程)结束时被JNI的DestroyJavaVM方法调用。
注意:当我们杀死进程时使用了kill -9时,由于程序无法捕获处理,进程被直接杀死,所以无法执行ShutdownHook。
参考:
1、ShutdownHook原理
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。