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

前言

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

正文

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)

运行结果:

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

原文发布于微信公众号 - zhisheng(zhisheng_blog)

原文发表时间:2018-09-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏SDNLAB

Open vSwitch系列之openflow版本兼容

众所周知Open vSwitch支持的openflow版本从1.0到1.5版本(当前Open vSwitch版本是2.3.2)通过阅读代码,处理openflow...

56613
来自专栏Java架构师学习

带你深入了解Java线程中的那些事

引言 说到Thread大家都很熟悉,我们平常写并发代码的时候都会接触到,那么我们来看看下面这段代码是如何初始化以及执行的呢? public class Thre...

3318
来自专栏Seebug漏洞平台

Jenkins 未授权远程代码执行漏洞(CVE-2017-1000353)

漏洞概要 Jenkins 未授权远程代码执行漏洞, 允许攻击者将序列化的Java SignedObject对象传输给Jenkins CLI处理,反序列化Obj...

4116
来自专栏Elasticsearch实验室

Elasitcsearch 底层系列 Lucene 内核解析之 Doc Value

       Elasticsearch 支持行存和列存,行存用于以文档为单位顺序存储多个文档的原始内容,在 Elasitcsearch 底层系列 Lucene...

3775
来自专栏开发技术

spring-boot-2.0.3不一样系列之源码篇 - run方法(三)之createApplicationContext,绝对有值得你看的地方

  此系列是针对springboot的启动,旨在于和大家一起来看看springboot启动的过程中到底做了一些什么事。如果大家对springboot的源码有所研...

5343
来自专栏大内老A

WCF技术剖析之二十六:如何导出WCF服务的元数据(Metadata)[实现篇]

元数据的导出就是实现从ServiceEndpoint对象向MetadataSet对象转换的过程,在WCF元数据框架体系中,元数据的导出工作由MetadataEx...

2285
来自专栏GreenLeaves

C# 文件读写系列二

读取文件原则上非常简单,但它不是通过FileInfo和DirectoryInfo来完成的,关于FileInfo和DirectoryInfo请参考C# 文件操作系...

3249
来自专栏一个番茄说

让你在WebView中用JS调Native Object

之所做这个东西,源于之前项目中需要把一些页面用webView来呈现,但是web中需要调用native的方法,比如获取本地存的某些数据、调用摄像头等等,这里也就是...

1083
来自专栏小灰灰

SpringMVC返回图片的几种方式

主要借助的是 HttpServletResponse这个对象,实现case如下

2557
来自专栏纯洁的微笑

Guava 源码分析(Cache 原理【二阶段】)

在上文「Guava 源码分析(Cache 原理)」中分析了 Guava Cache 的相关原理。

1781

扫码关注云+社区

领取腾讯云代金券