背景

用户:货都到了,购物车里怎么还有刚买的东西,what?

产品:有用户反映,提单完成了,怎么没清购物车,研发赶紧看看是不是有bug啊?

研发:恩,我看看,!@#¥%……&*()一顿狂查,搜嘎,当时在上线,重启应用,异步任务丢了……

产品:能不能行,上线你就丢任务,丢不丢人啊!

研发:…………

上线!重启!你还在为丢失任务而烦恼么?看这里看这里,从此不再丢任务,JVM可以安全退出的

在交易流程中,为了提升服务的性能,我们做了一些异步化的优化,比如更新用户最近使用的收货地址、提单完成后通过MQ去发送各种通知类消息、清理用户的购物车等等这些操作,异步化加快了应用的响应速度同时也带来一个隐患,如何保障异步操作的执行?这个场景主要发生在应用重启时,对于通过线程或线程池进行的异步化,JVM重启时,后台执行的异步操作可能尚未完成。这时,需要通过JVM安全关闭来保证异步操作进行完成后,JVM再执行关闭。

更广泛的说,在Linux上很多应用通常会通过kill -9 pid的方式强制将进程杀掉,这种方式简单高效,因此很多应用的停止脚本经常会选择使用kill -9 pid的方式。强制进程退出,会带来一些副作用,对应用程序而言其效果等同于突然掉电,可能会导致如下一些问题:

缓存中的数据尚未持久化到磁盘中,导致数据丢失;

正在进行文件的write操作,没有更新完成,突然退出,导致文件损坏;

线程池的任务队列中尚有接收到的任务还没来得及处理,导致任务丢失;

数据库操作已经完成,例如账户余额更新,准备返回应答消息给客户端时,消息尚在通信线程的发送队列中排队等待发送,进程强制退出导致应答消息没有返回给客户端,客户端发起超时重试,会带来重复更新问题;

其它问题等…

这些问题都有可能对我们的业务产生影响,造成不必要的损失,为了避免这些问题,我们需要在JVM关闭时做些扫尾的工作,为此JVM提供了关闭钩子(shutdown hooks)来做这些事情。本文探讨了利用关闭钩子的相关内容。

JVM 关闭

首先,我们了解下哪些情况会导致JVM关闭,如下图

在这里插入图片描述

对于强制关闭的几种情况,系统关机,操作系统会通知JVM进程关闭并等待,一旦等待超时,系统会强制中止JVM进程;kill -9、Runtime.halt()、断电、系统crash这些种方式会直接无商量中止JVM进程,JVM完全没有执行扫尾工作的机会。因此对用应用程序而言,我们强烈不建议使用kill -9 这种暴力方式退出。

而对于正常关闭、异常关闭的几种情况,JVM关闭前,都会调用已注册的shutdown hooks,基于这种机制,我们可以将扫尾的工作放在shutdown hooks中,进而使我们的应用程序安全的退出。基于平台通用性的考虑,我们更推荐应用程序使用System.exit(0)这种方式退出JVM。

JVM 与 shutdown hooks 交互流程如下图所示,可以对照源码进一步的学习shutdown hooks工作原理。

在这里插入图片描述

Jvm安全退出

对于tomcat类Web应用,我们可以直接通过Runtime.addShutdownHook(Thread hook)注册自定义钩子,在钩子中实现资源的清理;而对于worker类应用,我们可以采用如下的方式安全的退出应用。

基于信号的进程通知机制

信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。通俗来讲,信号就是进程间的一种异步通信机制。信号具有平台相关性,Linux平台支持的一些终止进程信号如下所示:

在这里插入图片描述

信号选择:为了不干扰正常信号的运作,又能模拟Java异步通知,在Linux上我们需要先选定一种特殊的信号。通过查看信号列表上的描述,发现 SIGUSR1 和 SIGUSR2 是允许用户自定义的信号,我们可以选择SIGUSR2,在Windows上我们可以选择SIGINT。

通过这种信号机制,对应用程序JVM发送特定信号,JVM可以感知并处理该信号,进而可以接受程序退出指令。

安全退出实现

首先看下通用的JVM安全退出的流程图:

在这里插入图片描述

第一步,应用进程启动的时候,初始化Signal实例,它的代码示例如下:

1 Signal sig = new Signal(getOSSignalType());

其中Signal构造函数的参数为String字符串,也就上文介绍的信号量名称。

第二步,根据操作系统的名称来获取对应的信号名称,代码如下:

1 private String getOSSignalType()

2 {

3 return System.getProperties().getProperty("os.name").

4 toLowerCase().startsWith("win") ? "INT" : "USR2";

5 }加Q君样:

756584822一起吹水聊天

判断是否是windows操作系统,如果是则选择SIGINT,接收Ctrl+C中断的指令;否则选择USR2信号,接收SIGUSR2(等价于kill -12 pid)指令。

第三步,将实例化之后的SignalHandler注册到JVM的Signal,一旦JVM进程接收到kill -12 或者 Ctrl+C则回调handle接口,代码示例如下:

1 Signal.handle(sig, shutdownHandler);

其中shutdownHandler实现了SignalHandler接口的handle(Signal sgin)方法,代码示例如下:

1 public class ShutdownHandler implements SignalHandler {

2 /**

3 * 处理信号

4 *

5 * @param signal 信号

6 */

7 public void handle(Signal signal) {

8 }

9 }

第四步,在接收到信号回调的handle接口中,初始化JVM的ShutdownHook线程,并将其注册到Runtime中,示例代码如下:

1 private void registerShutdownHook()

2 {

3 Thread t = new Thread(new ShutdownHook(), "ShutdownHook-Thread");

4 Runtime.getRuntime().addShutdownHook(t);

5 }

第五步,接收到进程退出信号后,在回调的handle接口中执行虚拟机的退出操作,示例代码如下:

1 Runtime.getRuntime().exit(0);

JVM退出时,底层会自动检测用户是否注册了ShutdownHook任务,如果有,则会自动执行注册钩子的Run方法,应用只需要在ShutdownHook中执行扫尾工作即可,示例代码如下:

1 class ShutdownHook implements Runnable

2 {

3 @Override

4 public void run() {

5 System.out.println("ShutdownHook execute start...");

6 try {

7 TimeUnit.SECONDS.sleep(10);//模拟应用进程退出前的处理操作

8 } catch (InterruptedException e) {

9 e.printStackTrace();

10 }

11 System.out.println("ShutdownHook execute end...");

12 }

13 }加Q君样:

756584822一起吹水聊天

通过以上的几个步骤,我们可以轻松实现JVM的安全退出,另外,通常安全退出需要有超时控制机制,例如30S,如果到达超时时间仍然没有完成退出,则由停机脚本直接调用kill -9强制退出。

使用关闭钩子的注意事项

关闭钩子本质上是一个线程(也称为Hook线程),对于一个JVM中注册的多个关闭钩子它们将会并发执行,所以JVM并不保证它们的执行顺序;由于是并发执行的,那么很可能因为代码不当导致出现竞态条件或死锁等问题,为了避免该问题,强烈建议在一个钩子中执行一系列操作。

Hook线程会延迟JVM的关闭时间,这就要求在编写钩子过程中必须要尽可能的减少 -

Hook线程的执行时间,避免hook线程中出现耗时的计算、等待用户I/O等等操作。

关闭钩子执行过程中可能被强制打断,比如在操作系统关机时,操作系统会等待进程停止,等待超时,进程仍未停止,操作系统会强制的杀死该进程,在这类情况下,关闭钩子在执行过程中被强制中止。

在关闭钩子中,不能执行注册、移除钩子的操作,JVM将关闭钩子序列初始化完毕后,不允许再次添加或者移除已经存在的钩子,否则JVM抛出 IllegalStateException。

不能在钩子调用System.exit(),否则卡住JVM的关闭过程,但是可以调Runtime.halt()。

Hook线程中同样会抛出异常,对于未捕捉的异常,线程的默认异常处理器处理该异常,不会影响其他hook线程以及JVM正常退出。

总结

为了保障应用重启过程中异步操作的执行,避免强制退出JVM可能产生的各种问题,我们可以采用关闭钩子、自定义信号的方式,主动的通知JVM退出,并在JVM关闭前,执行应用程序的一些扫尾工作,进一步保证应用程序可以安全的退出。

点击链接加入群聊【Java交流圈】

java 关闭另一个jvm_JVM安全退出(如何优雅的关闭java服务)相关推荐

  1. python如何关闭电脑_程序员应该如何优雅地关闭电脑?

    有时候我出去玩,不想回实验室关机,怎么办呢?刚好最近在学习python,能不能利用这个实现一下.可以利用微博提供的API实现python机器人登陆微博,发一条微博就相当于给电脑发一个指令,想法不错,就 ...

  2. java语言描述一个行为_设计模式之责任链模式——Java语言描述

    责任链模式为请求创建了一个接受者对象的链.这种模式给予请求的类型,对请求的发送者和接受者进行解耦.这种类型的设计模式属于行为模式.在这种模式下,通常每个接收者都包含对另一个接收者的引用.如果一个对象不 ...

  3. 简易售货机JAVA sql_求一个简易自动售货机的代码(java)要用创建类封装性,输出的时候要有提示语句,代码类似以下图片...

    展开全部 //Example类文件Example.java package cn.zhouhan; import java.util.Scanner; public class Example { s ...

  4. java如何关闭线程池_如何优雅的关闭Java线程池

    ⾯试中经常会问到,创建⼀个线程池需要哪些参数.线程池的工作原理,却很少会问到线程池如何安全关闭的. 也正是因为⼤家不是很关注这块,即便是⼯作三四年的⼈,也会有因为线程池关闭不合理,导致应用⽆法正常st ...

  5. vmx进程已提前退出_如何优雅地停止Java进程

    目录 理解停止Java进程的本质 应该如何正确地停止Java进程如何注册关闭钩子使用关闭钩子的注意事项信号量机制 总结 理解停止Java进程的本质 我们知道,Java程序的运行需要一个运行时环境,即: ...

  6. 怎么在java中创建一个自定义的collector

    文章目录 简介 Collector介绍 自定义Collector 总结 怎么在java中创建一个自定义的collector 简介 在之前的java collectors文章里面,我们讲到了stream ...

  7. java实现的一个发送手机短信

    利用java实现的一个发送手机短信的小例子 JAVA发送手机短信,流传有几种方法:(1)使用webservice接口发送手机短信,这个可以使用sina提供的webservice进行发送,但是需要进行注 ...

  8. java中collector使用_怎么在java中创建一个自定义的collector

    怎么在java中创建一个自定义的collector 简介 在之前的java collectors文章里面,我们讲到了stream的collect方法可以调用Collectors里面的toList()或 ...

  9. 雷卷 java,阿里巴巴资深技术专家雷卷:值得开发者关注的 Java 8 后时代的语言特性...

    阿里巴巴资深技术专家雷卷:值得开发者关注的 Java 8 后时代的语言特性 发布时间:2020-07-04 08:25:36 来源:51CTO 阅读:315 作者:阿里系统软件技术 栏目:云计算 作者 ...

最新文章

  1. 《研磨设计模式》chap8 生成器模式Builder
  2. 计算机里的东西不小心删除如何恢复,原先在电脑界面上的文件不小心删除了怎么恢复,谢谢了...
  3. Leetcode905.Sort Array By Parity按奇偶排序数组
  4. 设置单元格填充方式_【WPS神技能】Excel表格中单元格内的双色填充效果有点意思!...
  5. 游戏计算机软著登记证书,“VR沙盘游戏心理疗法软件”取得计算机软件著作权登记证书...
  6. python 中的堆栈 用列表实现
  7. php基础:变量命名、传值、检测、类型转换、动态变量名
  8. RecycleView 使用GridView样式列表添加头部
  9. python自动化转码屏幕录像专家exe为mp4
  10. ios睡眠分析 卧床 睡眠_AutoSleep 5 测评:一款自动化监测睡眠的 iOS + watchOS App
  11. echarts的legend显示不全_【报Bug】echarts图表的legend没有显示
  12. Python简单实现人脸识别检测, 对某平台美女主播照片进行评分排名
  13. 从谷歌搜获更多~[一些谷歌搜索的提示和技巧]
  14. Elementui蓝色阴影边框相关问题的解决方案
  15. 机器人出魔切还是三相_UZI卡莎五分钟魔切,绝境四杀带领队伍走向胜利?观众:永远滴神...
  16. 教你如何拥有好看的CMD界面 如何美化Windows Terminal
  17. PBR中引入IBL——镜面反射篇
  18. 什么软件可以测试自己的穿衣,心理测试:4个女孩,哪个穿衣风格跟你最像?秒测你的真实性格...
  19. 适用的验厂考勤工资AB账系统软件这样选择
  20. 趋高智能注塑件表面视觉检测之机器视觉的缺陷检测方案

热门文章

  1. android闹钟提醒
  2. 今天的移动支付,还是很不安全[转]
  3. 华夏幸福产业研究院顾强:从极限通勤看都市圈规划与发展
  4. Code Snippets
  5. Async/Await替代Promise的6个理由
  6. portal开发下拉框“日期框”查询要怎么配置
  7. Linux程序编译速度提高方法
  8. java输出一个Int数据的补码
  9. CISCO协议总结大全
  10. 【整理】内向交货(Inbound Delivery)