想象一下,如果你现在刚好在 word 上写需求文档,电脑突然重启。等待开机完成,你可能会发现写了一个小时文档没有保存,就这么没了。。。

一个正在运行 Java 应用如果突然将其停止,影响不止数据丢失,还会造成其他影响。比如:

  • 请求丢失:内存队列中等待执行请求丢失
  • 数据丢失:处于内存缓存中数据未持久化到磁盘
  • 文件损坏:正在写的文件没有没有更新完成,导致文件损坏
  • 业务中断:处理一半的业务被强行中断,如支付成功了,却没有更新到数据库中
  • 服务未下线:上游服务依然往停止节点发送请求

所以在关闭服务之前,我们需要先做好善后工作,比如保存数据,清理资源,下线服务,然后才退出应用。这种有计划平滑的关闭应用相对直接停止应用,就显得非常『优雅』。

ps: 仔细品味,优雅停机这个词真好~

ShutdownHook

Java 语言提供一种 ShutdownHook(钩子)进制,当 JVM 接受到系统的关闭通知之后,调用 ShutdownHook 内的方法,用以完成清理操作,从而平滑的退出应用。

ShutdownHook代码如下:

        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("关闭应用,释放资源");
}));

Runtime.getRuntime().addShutdownHook(Thread) 需要传入一个线程对象,后续动作将会在该异步线程内完成。除了主动关闭应用(使用 kill -15 指令),以下场景也将会触发 ShutdownHook :

  • 代码执行结束,JVM 正常退出
  • 应用代码中调用 System#exit 方法
  • 应用中发生 OOM 错误,导致 JVM 关闭
  • 终端中使用 Ctrl+C(非后台运行)

目前很多开源框架都是基于这个机制实现优雅停机,比如 Dubbo,Spring 等。

相关注意点

ShutdownHook 代码实现起来相对简单,但是我们还是需要小心下面这些坑。

Runtime.getRuntime().addShutdownHook(Thread) 可以被多次调用

我们可以多次调用 Runtime.getRuntime().addShutdownHook(Thread) 方法,从而增加多个。但是需要注意的是,多个 ShutdownHook 之间并无任何顺序,Java 并不会按照加入顺序执行,反而将会并发执行。

所以尽量在一个 ShutdownHook 完成所有操作。

ShutdownHook 需要尽快执行结束

不要在 ShutdownHook 执行需要被阻塞代码,如 I/0 读写,这样就会导致应用短时间不能被关闭。

 Runtime.getRuntime().addShutdownHook(new Thread(() -> {
while (true){
System.out.println("关闭应用,释放资源");
}
}));

上面代码中,我们使用 while(true) 模拟长时间阻塞这种极端情况,关闭该应用时,应用将会一直阻塞在 while 代码中,导致应用没办法被关闭。

除了阻塞之外,还需要小心其他会让线程阻塞的行为,比如死锁。

为了避免 ShutdownHook 线程被长时间阻塞,我们可以引入超时进制。如果等待一定时间之后,ShutdownHook 还未完成,由脚本直接调用 kill -9 强制退出或者 ShutdownHook 代码中引入超时进制。

文章首发于studyidea.cn/shutdownHook

欢迎关注我的公众号:程序通事,获得日常干货推送。如果您对我的专题内容感兴趣,也可以关注我的博客:studyidea.cn

ShutdownHook- Java 优雅停机解决方案的更多相关文章

  1. JAVA优雅停机的实现

    最近在项目中需要写一个数据转换引擎服务,每过5分钟同步一次数据.具体实现是启动engine server后会初始化一个ScheduledExecutorService和一个ThreadPoolExec ...

  2. Java优雅停机

    Java的优雅停机通常通过注册JDK的ShootDownHook实现,当系统接受到退出指令后,首先标记系统处于退出状态,不再接受新的消息,然后将积压的消息处理完,最后调用资源回收接口将资源销毁,最后各 ...

  3. Dubbo 优雅停机演进之路

    一.前言 在 『ShutdownHook- Java 优雅停机解决方案』 一文中我们聊到了 Java 实现优雅停机原理.接下来我们就跟根据上面知识点,深入 Dubbo 内部,去了解一下 Dubbo 如 ...

  4. 哦,这就是java的优雅停机?(实现及原理)

    优雅停机? 这个名词我是服的,如果抛开专业不谈,多好的名词啊! 其实优雅停机,就是在要关闭服务之前,不是立马全部关停,而是做好一些善后操作,比如:关闭线程.释放连接资源等. 再比如,就是不会让调用方的 ...

  5. Java 技术栈中间件优雅停机方案设计与实现全景图

    欢迎关注公众号:bin的技术小屋,阅读公众号原文 本系列 Netty 源码解析文章基于 4.1.56.Final 版本 本文概要 在上篇文章 我为 Netty 贡献源码 | 且看 Netty 如何应对 ...

  6. 你的Kubernetes Java应用优雅停机了吗?

    Java 应用优雅停机 我们首先考虑下,一般在什么场景下数据会丢失呢? 升级服务时 pod重启时 服务器断电时 因为服务器断电属于极端情况,我们暂且不考虑.那就只有 Java 退出时我们要保证数据的完 ...

  7. Spring Boot 2.3.0正式发布:优雅停机、配置文件位置通配符新特性一览

    当大潮退去,才知道谁在裸泳..关注公众号[BAT的乌托邦]开启专栏式学习,拒绝浅尝辄止.本文 https://www.yourbatman.cn 已收录,里面一并有Spring技术栈.MyBatis. ...

  8. Dubbo源码学习--优雅停机原理及在SpringBoot中遇到的问题

    Dubbo源码学习--优雅停机原理及在SpringBoot中遇到的问题 相关文章: Dubbo源码学习文章目录 前言 主要是前一阵子换了工作,第一个任务就是解决目前团队在 Dubbo 停机时产生的问题 ...

  9. Spring Boot 系列:最新版优雅停机详解

    爱生活,爱编码,本文已收录架构技术专栏关注这个喜欢分享的地方. 开源项目: 分布式监控(Gitee GVP最有价值开源项目 ):https://gitee.com/sanjiankethree/cub ...

随机推荐

  1. codeforces 816 E. Karen and Supermarket(树形dp)

    题目链接:http://codeforces.com/contest/816/problem/E 题意:有n件商品,每件有价格ci,优惠券di,对于i>=2,使用di的条件为:xi的优惠券需要被 ...

  2. 电脑修改密码后,git push 报错unable to access

    电脑修改密码后,git push 时报错 remote: Permission to xxx A. fatal: unable to access  解决这个问题有两种方法,一种是界面修改,一种是命令 ...

  3. net core天马行空系列: 一个接口多个实现类,利用mixin技术通过自定义服务名,实现精准属性注入

    系列目录 1.net core天马行空系列:原生DI+AOP实现spring boot注解式编程 2.net core天马行空系列: 泛型仓储和声明式事物实现最优雅的crud操作 哈哈哈哈,大家好,我 ...

  4. Disruptor中shutdown方法失效,及产生的不确定性源码分析

    版权声明:原创作品,谢绝转载!否则将追究法律责任. Disruptor框架是一个优秀的并发框架,利用RingBuffer中的预分配内存实现内存的可重复利用,降低了GC的频率. 具体关于Disrupto ...

  5. Java 添加Word文本框

    在Word中,文本框是指一种可移动.可调节大小的文字或图形容器.我们可以向文本框中添加文字.图片.表格等对象,下面,将通过Java编程来实现添加以上对象到Word文本框. 使用工具:Free Spir ...

  6. Jmeter 之 逻辑控制器 if 控制器

    最近工作不忙,利用空闲时间整理了下Jmeter的相关知识,下面给大家分享下Jmeter中 如果(if)控制的使用和应用. 如下图:线程组 > 添加 > 逻辑控制器 > 如果 (if) ...

  7. Linux安装yum install gcc-c++出错:Could not retrieve mirrorlist http://mirrorlist.centos.org/?release=7&arch=x86_64&repo=os&infra=stock error was 14: curl#6 - "Could not resolve host: mirrorlist.centos...

    错误如图: 解决办法: 1.修改配置文件 /etc/resolv.conf,该配置文件如下: 2.输入:gedit resolv.conf,修改配置文件内容如下: 3.然后重启: 4.重新进行安装: ...

  8. Maven学习归纳(五)——继承与聚合实例讲解

    一.Maven的继承 1.1 什么是继承? 继承:父工程拆分出很多子工程,可以通过父工程,统一管理依赖的版本 1.2 为什么要使用继承呢? 在A.jar 依赖着——>B.jar依赖着——> ...

  9. 洛谷 P3952时间复杂度 (本地AC测评RE的伪题解)

    [题目描述] 小明正在学习一种新的编程语言 A++,刚学会循环语句的他激动地写了好多程序并 给出了他自己算出的时间复杂度,可他的编程老师实在不想一个一个检查小明的程序, 于是你的机会来啦!下面请你编写 ...

  10. 并发之初章Java内存模型

    >>>>>>博客地址<<<<<< >>>>>>首发博客<<<<< ...