背景

在开发中,遇到这种情况,多个线程同时工作,突然一个线程遇到了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. Word2007文档中怎么输入上标下标

    1.Word中输出Z = X2 + Y2 此公式流程: 首先在Word中写入:Z = X2 + Y2: 方法1:选中X后面的2,再按组合键“Ctrl+Shift+加号键”即可,如此操作Y后面的2即可.

  2. VMware Workstation 14 pro License Keys

    AC5XK-0ZD4H-088HP-9NQZV-ZG2R4 CG54H-D8D0H-H8DHY-C6X7X-N2KG6 ZC3WK-AFXEK-488JP-A7MQX-XL8YF ZC5XK-A6E0 ...

  3. [真题] 一道 vsftp 运维题

    一道 vsftp 运维题 一.前言 在 V 站上凑巧看到了好友发的求助帖,五天时间一个理他的都没有.哈哈哈~ 废话不多说,我们来试试. 二.题目 这里我们假设存在这样的场景: 网络内有普通用户 ade ...

  4. 架构师养成记--34.Redis持久化

    ---恢复内容开始--- redis是一个支持持久化的内存数据库,也就是搜redis需要经常将内存中的数据同步到硬盘来保证持久化.redis持久化有两种方式. snapshotting(快照)默认方式 ...

  5. mysql工具——mysqlcheck(MYISAM)

    基本介绍 演示: 使用optimize的时候,可能会出现 Table does not support optimize, doing recreate + analyze instead 这时候参考 ...

  6. 洛谷P3980 [NOI2008]志愿者招募

    题解 最小费用最大流 每一天是一条边\((inf-a[i], 0)\) 然后对于一类志愿者, 区间两端连一条\((inf, c[i])\) \(S\)向第一个点连\((inf, 0)\) 最后一个点向 ...

  7. Powershell cannot be loaded because running scripts is disabled on this system 解决办法

    问题背景 第一次跑ps时,出现了下面的提示.这是因为windows不允许执行脚本而已,不要大惊小怪. 解决办法 这个需要管理员执行,不然会出现以下的情况 正常情况

  8. Mac OS 10.12使用U盘重装(转)

    OS X Capitan和macOS Sierra的安装方式和下载系统的方法都是一致的,下面是OS X Capitan的安装方法: 一.准备工作: 准备一个8GB或者8G以上容量的U盘 确保里面的数据 ...

  9. (转)漫谈JVM

    漫谈JVM 原文:https://liuzhengyang.github.io/2016/10/05/gossip-jvm/ 背景介绍 JVM已经是Java开发的必备技能了,JVM相当于Java的操作 ...

  10. C#集合通论

    前言 写这篇文章的最初动力是来自于一次笔试经历.有一道笔试题大概是这样的:程序使用一个txt文件来存储操作记录.存储记录是多行字符串,每一行代表一次操作记录,格式如下:用户名+操作事项名称+操作时间. ...