在看源码时,发现了 Runtime.getRuntime().addShutdownHook 的用法,看起来是在jvm退出前做了一些清理工作
Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { LOGGER.info("shut down cat client in runtime shut down hook!"); shutdown(); } });
抱着好奇的心态看了下addShutdownHook源码,结合方法描述总结如下:
这是注册一个虚拟机的shutdown hook
1. JVM 虚拟机会对以下两种情况下的shuts down 事件作出响应:
程序正常退出 - exit
也就是最后一个非守护线程退出或者调用了System.exit 方法退出
虚拟机由于被中断而退出 - terminated
ctrl + c 或者 系统事件如 用户登出(user logoff) 或者 系统shutdown (system shutdown)
2. 不建议在shutdown hooks 中运行耗时长的任务(long-running),任务最好能快速的运行完
当程序退出时,期望虚拟机也能及时的shutdown and exit
当虚拟机由于用户登出或者系统shutdown 而退出(terminated)时,底层操作系统可能只允许一个固定的时间(a fixed amount of time)来shutdown and exit
3. 在极少数情况下,虚拟机有可能会终止(abort),在这种情况下不会保证shutdown hooks是否会被执行
这里的abort 指的是虚拟机由于外部的信号而退出,比如unix的signal或者windows中的 TerminateProcess
4. 注册的hooks会并发的无序执行
调用ApplicationShutdownHooks.add方法,注册hook,当程序退出时,jvm 调用runHooks方法,并发的执行所有hook线程,直到所有线程执行完毕后退出
public void addShutdownHook(Thread hook) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new RuntimePermission("shutdownHooks")); } //调用add方法,将任务加入内存 ApplicationShutdownHooks.add(hook); }
ApplicationShutdownHooks
static synchronized void add(Thread hook) { if(hooks == null) throw new IllegalStateException("Shutdown in progress"); if (hook.isAlive()) throw new IllegalArgumentException("Hook already running"); if (hooks.containsKey(hook)) throw new IllegalArgumentException("Hook previously registered"); //hooks是一个map IdentityHashMap<Thread, Thread> hooks hooks.put(hook, hook); } //执行hooks static void runHooks() { Collection<Thread> threads; synchronized(ApplicationShutdownHooks.class) { threads = hooks.keySet(); hooks = null; } // 并发的执行hook for (Thread hook : threads) { hook.start(); } //直到所有的线程执行完退出 for (Thread hook : threads) { try { hook.join(); } catch (InterruptedException x) { } } }