您的位置:首页 > 编程语言 > Java开发

JAVA虚拟机关闭钩子(Shutdown Hook)

2021-04-02 21:26 756 查看

前言

当你认真的去看一个组件的源码的时候,你会经常看见这种关闭钩子的函数,如果你不了解的话,谷歌一下,你就会发现如下文章就是搜索引擎出来的第一篇,不愧是出自我们优秀的厮哒哒之笔。

正文

Java 程序经常也会遇到进程挂掉的情况,一些状态没有正确的保存下来,这时候就需要在 JVM 关掉的时候执行一些清理现场的代码。JAVA 中的 ShutdownHook 提供了比较好的方案。

JDK提供了Java.Runtime.addShutdownHook(Thread hook)方法,可以注册一个JVM关闭的钩子,这个钩子可以在一下几种场景中被调用:

1、程序正常退出

2、使用 System.exit()

3、终端使用 Ctrl+C 触发的中断

4、系统关闭

5、OutOfMemory 宕机

6、使用 Kill pid 命令干掉进程(注:在使用 kill -9 pid 时,是不会被调用的)

下面

是JDK1.7中关于钩子的定义:

public void addShutdownHook(Thread hook)

参数:
hook - An initialized but unstarted Thread object 

抛出: 

IllegalArgumentException - If the specified hook has already been registered, or if it can be determined that the hook is already running or has already been run 
IllegalStateException - If the virtual machine is already in the process of shutting down 
SecurityException - If a security manager is present and it denies RuntimePermission("shutdownHooks")

从以下版本开始: 
1.3 

另请参见:
removeShutdownHook(java.lang.Thread), halt(int), exit(int)

首先来测试第一种

程序正常退出的情况

1package com.hook;
2
3import java.util.concurrent.TimeUnit;
4
5public class HookTest
6{
7    public void start()
8    {
9        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
10            @Override
11            public void run()
12            {
13                System.out.println("Execute Hook.....");
14            }
15        }));
16    }
17
18    public static void main(String[] args)
19    {
20        new HookTest().start();
21        System.out.println("The Application is doing something");
22
23        try
24        {
25            TimeUnit.MILLISECONDS.sleep(5000);
26        }
27        catch (InterruptedException e)
28        {
29            e.printStackTrace();
30        }
31    }
32}

运行结果:

1The Application is doing something
2Execute Hook.....

如上可以看到,当main线程运行结束之后就会调用关闭钩子。

下面再来测试第五种情况(顺序有点乱,表在意这些细节)

OutOfMemory 宕机

1package com.hook;
2
3import java.util.concurrent.TimeUnit;
4
5public class HookTest2
6{
7    public void start()
8    {
9        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
10            @Override
11            public void run()
12            {
13                System.out.println("Execute Hook.....");
14            }
15        }));
16    }
17
18    public static void main(String[] args)
19    {
20        new HookTest().start();
21        System.out.println("The Application is doing something");
22        byte[] b = new byte[500*1024*1024];
23        try
24        {
25            TimeUnit.MILLISECONDS.sleep(5000);
26        }
27        catch (InterruptedException e)
28        {
29            e.printStackTrace();
30        }
31    }
32
33}

运行参数设置为:-Xmx20M 这样可以保证会有 OutOfMemoryError 的发生。

运行结果:

1The Application is doing something
2Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
3    at com.hook.HookTest2.main(HookTest2.java:22)
4Execute Hook.....

可以看到程序遇到内存溢出错误后调用关闭钩子,与第一种情况中,程序等待 5000ms 运行结束之后推出调用关闭钩子不同。

接下来再来测试第三种情况

终端使用 Ctrl+C 触发的中断

1package com.hook;
2
3import java.util.concurrent.TimeUnit;
4
5public class HookTest3
6{
7    public void start()
8    {
9        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
10            @Override
11            public void run()
12            {
13                System.out.println("Execute Hook.....");
14            }
15        }));
16    }
17
18    public static void main(String[] args)
19    {
20        new HookTest3().start();
21        Thread thread = new Thread(new Runnable(){
22
23            @Override
24            public void run()
25            {
26                while(true)
27                {
28                    System.out.println("thread is running....");
29                    try
30                    {
31                        TimeUnit.MILLISECONDS.sleep(100);
32                    }
33                    catch (InterruptedException e)
34                    {
35                        e.printStackTrace();
36                    }
37                }
38            }
39
40        });
41        thread.start();
42    }
43
44}

在命令行中编译:javac com/hook/HookTest3.java

在命令行中运行:java com.hook.HookTest3 (之后按下Ctrl+C)

运行结果:


可以看到效果如预期。 还有几种情况就不一一列出了,有兴趣的读者可以把剩余的几个也测试一下。

关注他


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: