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异常。

标签: java, Java面试题, Java下载, java教程, java技术, Java学习, Java学习教程, Java语言, Java开发, Java入门教程, Java进阶教程, Java高级教程, Java笔试题, Java编程思想