Java关闭挂钩– Runtime.addShutdownHook()
程序退出时,使用Java shutdown钩子可以方便地运行一些代码。
我们可以使用java.lang.Runtime.addShutdownHook(Thread t)方法在JVM中添加一个关闭钩子。
Java关闭钩子
在这两种情况下都将运行Java shutdown hook。
程序正常退出,或者我们调用
System.exit()
方法终止程序。
阅读有关Java系统类的更多信息。用户中断,例如Ctrl + C,系统关闭等。
有关Java Shutdown Hook的要点是:
我们可以使用Runtime的addShutdownHook()方法添加多个关闭钩子。
关闭挂钩是已初始化但未启动的线程。
它们在JVM关闭触发时启动。我们无法确定关机挂钩的执行顺序,就像执行多线程一样。
如果已启用退出完成,则将执行所有未调用的终结器。
无法保证关机钩子会执行,例如系统崩溃,kill命令等。
因此,仅应将其用于紧急情况下,例如确保释放关键资源等。您可以使用Runtime.getRuntime()。
removeShutdownHook(hook)方法删除钩子。启动关闭挂钩后,将无法删除它们。
您将得到IllegalStateException
。如果存在安全管理器并且它拒绝
RuntimePermission(" shutdownHooks")
,则将获得SecurityException。
Java关闭挂钩示例
因此,让我们来看一下Java中的shutdown钩子示例。
这是一个简单的程序,其中我从某个目录中逐行读取文件并进行处理。
我将程序状态保存在静态变量中,以便关机挂钩可以访问它。
package com.theitroad.shutdownhook; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FilenameFilter; import java.io.IOException; public class FilesProcessor { public static String status = "STOPPED"; public static String fileName = ""; public static void main(String[] args) { String directory = "/Users/hyman/temp"; Runtime.getRuntime().addShutdownHook(new ProcessorHook()); File dir = new File(directory); File[] txtFiles = dir.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { if (name.endsWith(".txt")) return true; else return false; } }); for (File file : txtFiles) { System.out.println(file.getName()); BufferedReader reader = null; status = "STARTED"; fileName = file.getName(); try { FileReader fr = new FileReader(file); reader = new BufferedReader(fr); String line; line = reader.readLine(); while (line != null) { System.out.println(line); Thread.sleep(1000); //assuming it takes 1 second to process each record //read next line line = reader.readLine(); } status = "PROCESSED"; } catch (IOException | InterruptedException e) { status = "ERROR"; e.printStackTrace(); }finally{ try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } status="FINISHED"; } }
上面代码中最重要的部分是第16行,我们其中添加了shutdown钩子,下面是实现类。
package com.theitroad.shutdownhook; public class ProcessorHook extends Thread { @Override public void run(){ System.out.println("Status="+FilesProcessor.status); System.out.println("FileName="+FilesProcessor.fileName); if(!FilesProcessor.status.equals("FINISHED")){ System.out.println("Seems some error, sending alert"); } } }
这是一种非常简单的用法,我只是在记录关闭钩子启动时的状态,如果还没有完成,则发送警报(实际上不是在这里记录它)。
让我们看看通过终端执行一些程序。
程序使用Ctrl + C命令终止。
如上图所示,当我们尝试使用Ctrl + C命令杀死JVM时,shutdown hook开始执行。程序正常执行。
请注意,即使在正常退出的情况下,钩子也会被调用,并且打印状态为完成。Kill Command终止JVM。
我使用了两个终端窗口向Java程序发射kill命令,因此操作系统终止了JVM,在这种情况下,未执行关闭钩子。