背景

在开发中,遇到这种情况,多个线程同时工作,突然一个线程遇到了fetal的错误,需要立即终止程序,等人工排查解决了问题之后重新启动。但是这样会有一个问题,程序终止时,其他线程可能正在进行重要操作,比如发一个message到另一个模块,并更新数据库状态。突然终止,可能会让这个操作只完成一半,从而导致数据不一致。

解决方案是:参考数据库Transaction原子性的概念,将这一系列重要操作看作一个整体,要么全部完成,要么全部不完成。为方便表述,我们把这一系列重要操作记为操作X。

当程序即将退出时,查看当前是否有操作X在执行中,

  • 如果有,等待其完成然后退出。且期间不再接受新的操作X。如果操作X执行之间过长,终止并回滚所有状态。
  • 如果没有,则可以立即退出。

在程序退出的时候,做一些Check,保证已经开始的操作X的原子性,这里就用到了Runtime.ShutdownHook

什么是Shutdown Hook

Shutdown hook是一个initialized but unstarted thread。当JVM开始执行shutdown sequence时,会并发运行所有registered Shutdown Hook。这时,在Shutdown Hook这个线程里定义的操作便会开始执行。

需要注意的是,在Shutdown Hook里执行的操作应当是不太耗时的。因为在用户注销或者操作系统关机导致的JVM shutdown的例子中,系统只会预留有限的时间给未完成的工作,超时之后还是会强制关闭。

什么时候会调用Shutdown Hook

  • 程序正常停止

    • Reach the end of program
    • System.exit
  • 程序异常退出
    • NPE
    • OutOfMemory
  • 受到外界影响停止
    • Ctrl+C
    • 用户注销或者关机

如何使用Shutdown Hook

调用java.lang.Runtime这个类的addShutdownHook(Thread hook)方法即可注册一个Shutdown Hook,然后在Thread中定义需要在system exit时进行的操作。如下:

Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println("Do something in Shutdown Hook")));

测试例子

首先,注册了一个Shutdown Hook

然后,系统Sleep 3秒,模拟进行某些操作。

然后,调用一个空的List,抛出异常,准备结束程序。

在程序将要结束的时候,执行Shutdown Hook中的内容。

public static void main(String[] args)
{
// register shutdown hook
Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println("Do something in Shutdown Hook"))); // sleep for some time
try {
for (int i=0; i<3; i++) {
System.out.println("Count: " + i + "...");
TimeUnit.MILLISECONDS.sleep(1000);
}
List nullList = new ArrayList<>();
System.out.println("Trying to print null list's first element: " + nullList.get(0).toString());
} catch (InterruptedException e) {
e.printStackTrace();
} System.out.println("Ready to exit.");
System.exit(0);
}

结果如下:

Count: 0...
Count: 1...
Count: 2...
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:653)
at java.util.ArrayList.get(ArrayList.java:429)
at HookTest.main(HookTest.java:18)
Do something in Shutdown Hook Process finished with exit code 1

需要注意的点

  • System.exit之后,当Shutdown Hook开始执行时,其他的线程还是会继续执行。
  • 应当保证Shutdown Hook的线程安全。
  • 在使用多个Shutdown Hook时一定要特别小心,保证其调用的服务不会被其他Hook影响。否则会出现当前Hook所依赖的服务被另外一个Hook终止了的情况。

链接

Java关闭钩子的应用 - Shutdown Hook的更多相关文章

  1. java 关闭钩子函数的应用

    Runtime.getRuntime().addShutdownHook(shutdownHook); 说明:这个方法的意思就是在jvm中增加一个关闭的钩子,当jvm关闭的时候,会执行系统中已经设置的 ...

  2. JAVA关闭钩子

    JAVA的关闭钩子: 1. 一般应用程序在关闭时都需要做一些善后清理工作,但是用户并不会总是按照推荐的方法关闭应用程序,比如用户直接关闭控制台程序或者按下Ctrl+C结束应用程序,这样就导致清理工作得 ...

  3. 关闭钩子(shutdown hook)的作用以及在Tomcat中的使用

    在很多实际应用环境中,当用户关了应用程序时,需要做一些善后清理工作,但问题是,用户有时并不会按照推荐的方法关闭应用程序,很有可能不做清理工作,例如在Tomcat的部署应用中,通过实例化一个Server ...

  4. Java Shutdown Hook 场景使用和源码分析

    我是陈皮,一个在互联网 Coding 的 ITer,微信搜索「陈皮的JavaLib」第一时间阅读最新文章,回复[资料],即可获得我精心整理的技术资料,电子书籍,一线大厂面试资料和优秀简历模板. 背景 ...

  5. java的关闭钩子(Shutdown Hook)

    Runtime.getRuntime().addShutdownHook(shutdownHook);    这个方法的含义说明:        这个方法的意思就是在jvm中增加一个关闭的钩子,当jv ...

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

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

  7. 关闭钩子(shutdown hook)的作用

    DK1.3介绍了java.lang.Runtime class的addShutdownHook()方法.如果你需要在你的程序关闭前采取什么措施,那么关闭钩子(shutdown hook)是很有用的. ...

  8. JAVA 虚拟机钩子

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

  9. Spark学习:ShutdownHookManager虚拟机关闭钩子管理器

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

随机推荐

  1. XorPay 个人支付平台增加 个人支付宝支付接口

      XorPay 今天新增 个人支付宝当面付 接口,欢迎大家使用. 「 XorPay 支付平台」 已经同时支持 个人微信支付接口 和 个人支付宝接口. 个人可用的 支付宝/微信支付 接口,支持 当面付 ...

  2. QuantLib 金融计算——基本组件之 Index 类

    目录 QuantLib 金融计算--基本组件之 Index 类 QuantLib 金融计算--基本组件之 Index 类 Index 类用于表示已知的指数或者收益率,例如 Libor 或 Shibor ...

  3. Ubuntu16.04安装视觉SLAM环境(g2o)

    1.首先在github上下载g2o图优化库 git clone https://github.com/RainerKuemmerle/g2o.git 2.运行安装以下依赖库 sudo apt-get ...

  4. python实现数据库增删改查

    column_dic = {"id": 0, "name": 1, "age": 2, "phone": 3, &quo ...

  5. LeetCode一句话题解

    深度优先搜索 人生经验 1. 需要输出所有解.并由于元素集有重复元素,要求返回的结果需要去重的情况,可考虑使用值对应数量的map,然后分别考虑依次取不同数量该值的可能. LeetCode39 题目:给 ...

  6. Spring框架初写

    1.Spring的概述 a)   Spring是什么 Spring是一个JavaEE轻量级的一站式 Java EE的开发框架. JavaEE: 就是用于开发B/S的程序.(企业级) 轻量级:使用最少代 ...

  7. 布局优化之ViewStub、Include、merge使用分析

    布局技巧 在Android开发过程中,我们会遇到很多的问题,随着UI界面越来越多,布局的重复性.复杂度也随之增加,所幸的是,Android官方也给出了几个对布局进行优化的方法,下面根据自己的理解对官方 ...

  8. Mac 10.12安装窗口快速缩放到一定比例的工具Moom

    说明:比如想要窗口只占用屏幕的一半时,我们的做法就是手动调节,而这款软件已经有快速按钮点一下即可. 下载: (链接: https://pan.baidu.com/s/1gfguJth 密码: wqjb ...

  9. Yii 使用Widge面面观

    我们可以把Widget视为一个嵌入到控制器管理 的视图中的微控制器,其实就是.net框架中的用户控件,或者类似于.net MVC中的子视图.与controller相比较,微件没有既没有动作,也没有过滤 ...

  10. (转)如何在CentOS / RHEL 7上安装Elasticsearch,Logstash和Kibana(ELK)

    原文:https://www.howtoing.com/install-elasticsearch-logstash-and-kibana-elk-stack-on-centos-rhel-7 如果你 ...