ShutdownHooks源码详解
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ShutdownHooks源码详解相关的知识,希望对你有一定的参考价值。
背景
在某些情况下,我们总希望在java application退出之前做一些资源清除的操作。比如:线程池,在应用关闭后仍然存活,从而造成服务宕机。而java正好给我们提供了这样的方法来关闭这些资源,ShutdownHooks. 接下来就将其涉及到的源码逐一解释。
使用场景
程序正常退出
使用System.exit()
终端使用Ctrl+C触发的中断
系统关闭
OutOfMemory宕机
使用Kill pid命令干掉进程(注:在使用kill -9 pid时,是不会被调用的)
Shutdown
它是关闭jvm的一个直接类,如System.exit(0). 包含JNI方法。
class Shutdown { //不能直接调用此类。通常是通过Runtime.getRuntime().addShutdownHook(thread)间接使用。 // shutdown的几个状态 private static final int RUNNING = 0; // application正在运行 private static final int HOOKS = 1; // 正在处理hooks private static final int FINALIZERS = 2; // 正在处理finalizers private static int state = RUNNING; // 默认为运行状态 // hook的数量,10个。 private static final int MAX_SYSTEM_HOOKS = 10; private static final Runnable[] hooks = new Runnable[MAX_SYSTEM_HOOKS]; private static int currentRunningHook = 0; // 添加hook。 // slot表示hooks的下标,也就是执行hook的顺序。 // registerShutdownInProgress表示是否在shutdown执行过程添加hook,通常是false. // hook表示的执行的线程。 static void add(int slot, boolean registerShutdownInProgress, Runnable hook) { synchronized (lock) { // 避免并发情况下的覆盖。 if (hooks[slot] != null) // 如果hooks对应的槽点已经有对应的hook,也不能添加。 throw new InternalError("Shutdown hook at slot " + slot + " already registered"); if (!registerShutdownInProgress) { // 表示执行shutdown过程中,不添加hook. if (state > RUNNING) // 如果已经在执行shutdown操作,则不能添加hook throw new IllegalStateException("Shutdown in progress"); } else { // 如果hooks已经执行完毕,则不能再添加hook。如果正在执行hooks时,添加的槽点小于当前执行的槽点位置,则也不能添加。 if (state > HOOKS || (state == HOOKS && slot <= currentRunningHook)) throw new IllegalStateException("Shutdown in progress"); } hooks[slot] = hook; // 对应槽点增加hook. } } // 执行所有注册的hooks 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; } } } } // 执行halt操作,也就是关闭JVM的操作 static void halt(int status) { synchronized (haltLock) { halt0(status); } } static native void halt0(int status); // JNI 真正的halt方法 // Wormhole for invoking java.lang.ref.Finalizer.runAllFinalizers private static native void runAllFinalizers(); // shutdown的执行顺序:runHooks > runFinalizersOnExit private static void sequence() { synchronized (lock) { if (state != HOOKS) return; } runHooks(); boolean rfoe; synchronized (lock) { state = FINALIZERS; rfoe = runFinalizersOnExit; } if (rfoe) runAllFinalizers(); } // 退出操作。runHooks > runFinalizersOnExit > halt static void exit(int status) { boolean runMoreFinalizers = false; synchronized (lock) { if (status != 0) runFinalizersOnExit = false; switch (state) { case RUNNING: state = HOOKS; break; case HOOKS: break; case FINALIZERS: if (status != 0) { halt(status); } else { runMoreFinalizers = runFinalizersOnExit; } break; } } if (runMoreFinalizers) { runAllFinalizers(); halt(status); } synchronized (Shutdown.class) { sequence(); halt(status); } } // shutdown操作,与exit不同的是,不做halt操作(关闭JVM) static void shutdown() { synchronized (lock) { switch (state) { case RUNNING: state = HOOKS; break; case HOOKS: case FINALIZERS: break; } } synchronized (Shutdown.class) { sequence(); } } }
ApplicationShutdownHooks
它是对Shutdown的一个代理类。主要是添加、删除hook的适配。
class ApplicationShutdownHooks { private static IdentityHashMap<Thread, Thread> hooks; // hook线程的存储器 // 初始化时,向Shutdown中添加hook.并初始化hooks容器。 static { try { Shutdown.add(1, false, 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; } } // 添加hook 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.put(hook, hook); } // 删除hook static synchronized boolean remove(Thread hook) { if(hooks == null) throw new IllegalStateException("Shutdown in progress"); if (hook == null) throw new NullPointerException(); return hooks.remove(hook) != null; } // 执行hook 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) { } } } }
Runtime
运行时执行类。
public class Runtime { private static Runtime currentRuntime = new Runtime(); // 静态的Runtime // 静态方法获取Runtime.这个也是获取runtime的单例方法。 public static Runtime getRuntime() { return currentRuntime; } // Shutdown.exit()退出的适配方法 public void exit(int status) { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkExit(status); } Shutdown.exit(status); } // 添加hook public void addShutdownHook(Thread hook) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new RuntimePermission("shutdownHooks")); } ApplicationShutdownHooks.add(hook); } // 删除hook public boolean removeShutdownHook(Thread hook) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new RuntimePermission("shutdownHooks")); } return ApplicationShutdownHooks.remove(hook); } // 关闭程序 public void halt(int status) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkExit(status); } Shutdown.halt(status); } 。。。 }
总结:
在Shutdown的执行顺序:
runHooks > runFinalizersOnExit > halt
Shutdown和ShutdownHooks不能被外部类直接调用,需要通过Runtime来代理操作。
应用实例
public class PollingServerListUpdater implements ServerListUpdater { static ScheduledThreadPoolExecutor _serverListRefreshExecutor = null; static { _serverListRefreshExecutor = new ScheduledThreadPoolExecutor(coreSize, factory); // 定时任务线程池 _shutdownThread = new Thread(new Runnable() { // shutdown hook public void run() { logger.info("Shutting down the Executor Pool for PollingServerListUpdater"); shutdownExecutorPool(); } }); Runtime.getRuntime().addShutdownHook(_shutdownThread); // 添加hook } // hook线程中的清理方法。 private static void shutdownExecutorPool() { if (_serverListRefreshExecutor != null) { _serverListRefreshExecutor.shutdown(); if (_shutdownThread != null) { try { Runtime.getRuntime().removeShutdownHook(_shutdownThread); } catch (IllegalStateException ise) { // NOPMD // this can happen if we're in the middle of a real // shutdown, // and that's 'ok' } } } } }
以上是关于ShutdownHooks源码详解的主要内容,如果未能解决你的问题,请参考以下文章
初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段
初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段