Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 11365|回复: 0

ShutdownHook - Java 优雅停机解决方案

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-4-12 16:52:56 | 显示全部楼层 |阅读模式

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

    其他平台.png

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-12-23 05:45 , Processed in 0.228983 second(s), 27 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表