JVM 进程退出是由于 JVM 进程中没有活跃的非守护线程,或者收到了系统中断信号,向 JVM 程序注入一个 Hook 线程,在 JVM 进程退出的时候, Hook 线程会启动执行,通过 Runtime 可以为 JVM 注入多个 Hook 线程。
示例
public static void main(String[] args) { Runtime.getRuntime().addShutdownHook(new Thread(()->{ try { System.out.println("the hook thread 1 is running."); TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("the hook thread 1 will exit."); })); Runtime.getRuntime().addShutdownHook(new Thread(()->{ try { System.out.println("the hook thread 2 is running."); TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("the hook thread 2 will exit."); })); System.out.println("The program will is stopping."); }输出
The program will is stopping. the hook thread 1 is running. the hook thread 2 is running. the hook thread 1 will exit. the hook thread 2 will exit.注意事项
Hook 线程只有在收到退出信号的时候会被执行,如果在 kill 的时候使用了参数 -9,那么 Hook 线程不会得到执行,进程将会立即退出。Hook 线程中也可以执行一些资源释放的工作。尽量不要再 Hook 线程中执行一些耗时非常长的操作,因为其会导致程序迟迟不能退出。API
public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) //某个线程指定 UncaughtExceptionHandler public UncaughtExceptionHandler getUncaughtExceptionHandler() //获取该线程指定的UncaughtExceptionHandler public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) //设置全局线程 UncaughtExceptionHandler public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() //获取全局线程 UncaughtExceptionHandlerUncaughtExceptionHandler
@FunctionalInterface public interface UncaughtExceptionHandler { /** * Method invoked when the given thread terminates due to the * given uncaught exception. * <p>Any exception thrown by this method will be ignored by the * Java Virtual Machine. * @param t the thread * @param e the exception */ void uncaughtException(Thread t, Throwable e); }该接口会被 Thread 中的 dispatchUncaughtException 方法调用。dispatchUncaughtException 方法只会被 JVM 调用。
/** * Dispatch an uncaught exception to the handler. This method is * intended to be called only by the JVM. */ private void dispatchUncaughtException(Throwable e) { getUncaughtExceptionHandler().uncaughtException(this, e); }getUncaughtExceptionHandler 方法
public UncaughtExceptionHandler getUncaughtExceptionHandler() { return uncaughtExceptionHandler != null ? uncaughtExceptionHandler : group; }其中 uncaughtExceptionHandler 变量为该线程指定的 UncaughtExceptionHandler,即调用 public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) 方法设置。
group 为线程组,其实现了 Thread.UncaughtExceptionHandler 接口。默认的 uncaughtException 方法为:
public void uncaughtException(Thread t, Throwable e) { if (parent != null) { parent.uncaughtException(t, e); } else { Thread.UncaughtExceptionHandler ueh = Thread.getDefaultUncaughtExceptionHandler(); if (ueh != null) { ueh.uncaughtException(t, e); } else if (!(e instanceof ThreadDeath)) { System.err.print("Exception in thread \"" + t.getName() + "\" "); e.printStackTrace(System.err); } } }如果父线程组不为 null ,会一直获取执行父线程组的 uncaughtException 方法,如果父线程组为 null ,则获取默认的,如果默认的不为 null,则会执行默认。