想象一下,如果你现在刚好在 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 - 1150 D Three Religions

    题目传送门 题解: id[ i ][ j ] 代表的是在第j个位置之后的第i个字符的位置在哪里. dp[ i ][ j ][ k ] 代表的是 第一个串匹配到第i个位置, 第二个串匹配到第j个位置, ...

  2. hdu 1028 Ignatius and the Princess III 母函数

    Ignatius and the Princess III Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K ...

  3. poj 3159 Candies(dijstra优化非vector写法)

    题目链接:http://poj.org/problem?id=3159 题意:给n个人派糖果,给出m组数据,每组数据包含A,B,c 三个数,意思是A的糖果数比B少的个数不多于c,即B的糖果数 - A的 ...

  4. http gzip压缩功能记录

    版权声明:本文为博主原创文章,转载请附上原文出处链接. 本文链接:https://www.cnblogs.com/shaoshuai95928/articles/Tomcat.html 最近在spri ...

  5. .NET 分布式自增Id组件(解决自动分配机器Id、时间回拨问题)

    目录 简介 产生背景 使用方式 原始版 完美版 测试 结尾 简介 IdHelper是一个.NET(支持.NET45+或.NET Standard2+)生成分布式趋势自增Id组件,有两个版本:原始版为基 ...

  6. SSM整合activiti框架

    一:WorkFlow简介 1:什么是工作流工作流(Workflow),指“业务过程的部分或整体在计算机应用环境下的自动化”.是对工作流程及其各操作步骤之间业务规则的抽象.概括描述.在计算机中,工作流属 ...

  7. VUE从入门到放弃(项目全流程)————VUE

    VUE从入门到放弃(第一天)--整体流程 先想想一个项目,vue项目是从什么到什么,然后再什么的?那是什么呢? 搭建 ( vue-cli) 代码内容 运行 封装 成品 一.搭建(脚手架vue-cli) ...

  8. git windows 安装 - Github同步 / Vscode源代码管理:Git 安装操作

    github上创建立一个项目 登录github网站,在github首页,点击页面右下角"New Repository" 最后点击"Create Repository&qu ...

  9. 启动第二个activity,然后返回数据给第一个数据

    第一个activity启动的代码: intent = new Intent(MainActivity.this, Main2Activity.class); startActivityForResul ...

  10. [AWS] Lambda by Python

    当前统治数据分析的语言还是Python,还是暂时走:Python + GPU的常规路线好了. numba, pyculib (分装了cublas) Ref: 使用 Python 构建 Lambda 函 ...