文章目录


高并发编程-Runtime.getRuntime().addShutdownHook为自己的应用添加hook_addShutdownHook

概述

高并发编程-Runtime.getRuntime().addShutdownHook为自己的应用添加hook_ide_02

一句话概括就是: 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​​ , 亲测有效,就不贴图了,自行验证即可。