概述
一句话概括就是: ShutdownHook允许开发人员在JVM关闭时执行相关的代码。
我们可以使用java.lang.Runtime.getRuntime().addShutdownHook(Thread t)
方法在JVM中添加关闭钩子。
使用场景
1.程序正常退出 , JVM关闭
2. 调用System.exit ,JVM关闭
3. 程序抛出异常,导致JVM关闭
4. OOM 导致JVM关闭
5. 外界:Ctrl + C ,导致JVM关闭
6. 外界:用户注销或者关机,导致JVM关闭
7. 外界:kill 信号 (kill -9 除外)
8. …
注意事项
1. 可以使用addShutdownHook()添加多个shutdown hooks
2. Shutdown hooks 是initialized 但是 not-started的线程,当JVM关闭时被触发
3. 无法确定shutdown hooks的执行顺序,就像执行多线程一样。
4. 无法保证shutdown hooks会执行,例如系统崩溃,kill命令等。因此,应仅将其用于紧急情况下,例如确保释放关键资源等。不要执行耗时操作
5. 可以使用Runtime.getRuntime().removeShutdownHook(hook)方法删除钩子。
6. 启动关闭挂钩后,无法删除,否则抛出IllegalStateException。
7. 如果存在security manager并且它拒绝RuntimePermission(“shutdownHooks”),则将抛出SecurityException。
示例
package com.artisan.test; import java.io.*; import java.util.ArrayList; import java.util.List; /** * Runtime.getRuntime().addShutdownHook Demo */ public class FileHandler { public static String status = "STOPPED"; public static String fileName = ""; public static void main(String[] args) { // 添加HOOK Runtime.getRuntime().addShutdownHook(new FileHandlerHook()); Runtime.getRuntime().addShutdownHook( new Thread(()->{ System.out.println("HOOK TRIGGERED:多个shutdown hook 被触发..."); })); // 文件目录 String directory = "E:\\hooktest"; File dir = new File(directory); // 列出txt结尾的文件 File[] txtFiles = dir.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { if (name.endsWith(".txt")) { return true; } else { return false; } } }); // 模拟触发Hook的情况 case 1 //System.exit(0); // 模拟触发Hook的情况 case 2 //int a = 1 / 0 ;他 // OOM // List list = new ArrayList(); // for(int i=0;i<Integer.MAX_VALUE;i++){ // list.add(i+"测试oom 导出jvm退出,触发hook"); // } // 遍历数组 读取文件 for (File file : txtFiles) { System.out.println("fileName:" + file.getName()); status = "START"; BufferedReader bufferedReader = null; try { FileReader fileReader = new FileReader(file); // BufferedReader一行行的读 提高读取效率 bufferedReader = new BufferedReader(fileReader); String line; // 先读取一行 line = bufferedReader.readLine(); // 循环读取 直到读取完成 while (line != null) { System.out.println(line); // 模拟业务 休眠一会 方便操作 Thread.sleep(1_111); line = bufferedReader.readLine(); } status = "PROCESSED"; } catch (IOException | InterruptedException e) { status = "ERROR"; e.printStackTrace(); } finally { try { bufferedReader.close(); } catch (IOException e) { e.printStackTrace(); } } } status = "FINISHED"; } private static class FileHandlerHook extends Thread { @Override public void run() { System.out.println("Status="+FileHandler.status); System.out.println("FileName="+FileHandler.fileName); if(!FileHandler.status.equals("FINISHED")){ System.out.println("HOOK TRIGGERED:Seems some error, sending alert...."); }else{ System.out.println("HOOK TRIGGERED:handle file over , Do Something notify...."); } } } }
上述代码以及覆盖了使用场景中的事项 ,使用哪个来做验证,放开对应注释即可。
OOM的测试,请设置jvm参数 -Xms10m -Xmx10m
, 亲测有效,就不贴图了,自行验证即可。