Java关闭挂钩– Runtime.addShutdownHook()

时间:2020-02-23 14:36:50  来源:igfitidea点击:

程序退出时,使用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,在这种情况下,未执行关闭钩子。