文章目录
概述
一句话概括就是: 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() {
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 {
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
, 亲测有效,就不贴图了,自行验证即可。