Java教程-Java关闭钩子

Java关闭钩子
Java关闭钩子是一种特殊的机制,它使开发人员能够在Java虚拟机(JVM)关闭时运行一些代码。在JVM关闭时需要执行一些特殊的清理工作时,Java关闭钩子非常有用。需要注意的是,当JVM由于一些外部因素而关闭时,无法使用通用构造处理在JVM终止之前调用特殊方法的操作。例如,每当操作系统生成终止请求或由于缺乏可用内存而无法分配资源时,就无法调用该过程。关闭钩子通过提供任意代码块来舒适地解决了这个问题。
从表面上看,了解关闭钩子是很简单的。只需要使用java.lang.Thread类派生一个类,并在JVM即将关闭时的run()方法中提供要执行的任务代码。要将派生类的实例注册为关闭钩子,需要调用Runtime.getRuntime().addShutdownHook(Thread)方法,而要删除已注册的关闭钩子,需要调用removeShutdownHook(Thread)方法。
简而言之,关闭钩子可用于在JVM正常或异常关闭时执行资源清理或保存状态。执行清理资源意味着关闭日志文件、发送警报或其他操作。因此,如果您想在JVM关闭之前执行一些代码,请使用关闭钩子。
JVM何时关闭?
JVM在以下情况下关闭:
- 用户在命令提示符上按下ctrl+c
- 调用System.exit(int)方法
- 用户注销
- 用户关机等。
addShutdownHook(Thread hook)方法
Runtime类的addShutdownHook()方法用于将线程注册到虚拟机中。
语法:
public void addShutdownHook(Thread hook){}
可以通过调用静态工厂方法getRuntime()获取Runtime类的对象。例如:
Runtime r = Runtime.getRuntime();
removeShutdownHook(Thread hook)方法
调用Runtime类的removeShutdownHook()方法来删除已注册的关闭钩子的注册。
语法:
public boolean removeShutdownHook(Thread hook){ }
方法成功取消注册已注册的钩子时返回true;否则返回false。
工厂方法
返回类的实例的方法称为工厂方法。
关闭钩子的简单示例
文件名:MyThread.java
class MyThread extends Thread{
public void run(){
System.out.println("shut down hook task completed..");
}
}
public class TestShutdown1{
public static void main(String[] args)throws Exception {
Runtime r=Runtime.getRuntime();
r.addShutdownHook(new MyThread());
System.out.println("Now main sleeping... press ctrl+c to exit");
try{Thread.sleep(3000);}catch (Exception e) {}
}
}
输出:
Now main sleeping... press ctrl+c to exit
shut down hook task completed.
使用匿名类的关闭钩子相同示例:
文件名:TestShutdown2.java
public class TestShutdown2{
public static void main(String[] args)throws Exception {
Runtime r=Runtime.getRuntime();
r.addShutdownHook(new Thread(){
public void run(){
System.out.println("shut down hook task completed..");
}
}
);
System.out.println("Now main sleeping... press ctrl+c to exit");
try{Thread.sleep(3000);}catch (Exception e) {}
}
}
输出:
Now main sleeping... press ctrl+c to exit
shut down hook task completed.
删除已注册的关闭钩子示例
以下示例演示了如何使用removeShutdownHook()方法来删除已注册的关闭钩子。
文件名:RemoveHookExample.java
public class RemoveHookExample
{
// Msg 类派生自 Thread 类
static class Msg extends Thread
{
public void run()
{
System.out.println("Bye ...");
}
}
//主要方法
public static void main(String[] argvs)
{
try
{
// 创建类 Msg 的对象
Msg ms = new Msg();
// 将 Msg 对象注册为关闭钩子
Runtime.getRuntime().addShutdownHook(ms);
// 打印程序的当前状态
System.out.println("The program is beginning ...");
// 使线程休眠 2 秒
System.out.println("Waiting for 2 seconds ...");
Thread.sleep(2000);
// 移除钩子
Runtime.getRuntime().removeShutdownHook(ms);
// 打印消息程序正在终止
System.out.println("The program is terminating ...");
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
输出:
The program is beginning ...
Waiting for 2 seconds ...
The program is terminating ...
需要记住的要点
在使用关闭钩子时需要记住一些重要的事项。
关闭钩子的执行不保证:首先,要记住的最重要的事情是,关闭钩子的执行没有确定性。在某些情况下,关闭钩子根本不会执行。例如,如果JVM由于某些内部错误而崩溃,那么关闭钩子就没有任何机会。当操作系统发出SYSKILL信号时,关闭钩子也无法发挥作用。
请注意,当应用程序正常终止时,关闭钩子会被调用(应用程序的所有线程已完成或终止)。此外,当操作系统关闭或用户按下ctrl+c时,关闭钩子会被调用。
在完成之前,可以强制停止关闭钩子:这是上述讨论的特殊情况。每当关闭钩子开始执行时,可以通过关闭系统来强制终止它。在这种情况下,操作系统会等待一定的时间。如果在这段时间内任务没有完成,系统就没有其他选择,只能强制终止正在运行的钩子。
可以有多个关闭钩子,但执行顺序不保证:JVM可以以任意顺序执行关闭钩子。甚至可以并发执行关闭钩子。
在关闭钩子中不允许注销或注册关闭钩子:当JVM启动关闭序列时,无法删除或添加任何现有的关闭钩子。如果尝试这样做,JVM会抛出IllegalStateException。
Runtime.halt()方法可以停止已启动的关闭序列:只有Runtime.halt()方法可以强制终止JVM,从而停止已启动的关闭序列,这也意味着在关闭钩子中调用System.exit()方法将无效。
在使用关闭钩子时需要安全权限:如果使用Java安全管理器,则负责删除或添加关闭钩子的Java代码需要在运行时获取关闭钩子的权限。如果在安全环境中未获取权限而调用该方法,则会引发SecurityException异常。