一、什么是ShutdownHook?

在Java程序中可以通过添加关闭钩子,实现在程序退出时关闭资源、平滑退出的功能。 
使用Runtime.addShutdownHook(Thread hook)方法,可以注册一个JVM关闭的钩子,这个钩子可以在以下几种场景被调用: 
1. 程序正常退出 
2. 使用System.exit() 
3. 终端使用Ctrl+C触发的中断 
4. 系统关闭 
5. 使用Kill pid命令干掉进程


Runtime.java中相关方法源码

public void addShutdownHook(Thread hook) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("shutdownHooks"));
}
ApplicationShutdownHooks.add(hook);
} public boolean removeShutdownHook(Thread hook) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("shutdownHooks"));
}
return ApplicationShutdownHooks.remove(hook);
}

ApplicationShutdownHooks.java

class ApplicationShutdownHooks {
/* The set of registered hooks */
private static IdentityHashMap<Thread, Thread> hooks;
static {
try {
Shutdown.add(1 /* shutdown hook invocation order */,
false /* not registered if shutdown in progress */,
new Runnable() {
public void run() {
runHooks();
}
}
);
hooks = new IdentityHashMap<>();
} catch (IllegalStateException e) {
// application shutdown hooks cannot be added if
// shutdown is in progress.
hooks = null;
}
} private ApplicationShutdownHooks() {} /* Add a new shutdown hook. Checks the shutdown state and the hook itself,
* but does not do any security checks.
*/
static synchronized void add(Thread hook) {
if(hooks == null)
throw new IllegalStateException("Shutdown in progress"); if (hook.isAlive())
throw new IllegalArgumentException("Hook already running"); if (hooks.containsKey(hook))
throw new IllegalArgumentException("Hook previously registered"); hooks.put(hook, hook);
} /* Remove a previously-registered hook. Like the add method, this method
* does not do any security checks.
*/
static synchronized boolean remove(Thread hook) {
if(hooks == null)
throw new IllegalStateException("Shutdown in progress"); if (hook == null)
throw new NullPointerException(); return hooks.remove(hook) != null;
} /* Iterates over all application hooks creating a new thread for each
* to run in. Hooks are run concurrently and this method waits for
* them to finish.
*/
static void runHooks() {
Collection<Thread> threads;
synchronized(ApplicationShutdownHooks.class) {
threads = hooks.keySet();
hooks = null;
} for (Thread hook : threads) {
hook.start();
}
for (Thread hook : threads) {
try {
hook.join();
} catch (InterruptedException x) { }
}
}
}

二、java进程平滑退出的意义

很多时候,我们会有这样的一些场景,比如说nginx反向代理若干个负载均衡的web容器,又或者微服务架构中存在的若干个服务节点,需要进行无间断的升级发布。 
在重启服务的时候,除非我们去变更nginx的配置,否则重启很可能会导致正在执行的线程突然中断,本来应该要完成的事情只完成了一半,并且调用方出现错误警告。 
如果能有一种简单的方式,能够让进程在退出时能执行完当前正在执行的任务,并且让服务的调用方将新的请求定向到其他负载节点,这将会很有意义。 
自己注册ShutdownHook可以帮助我们实现java进程的平滑退出。


三、java进程平滑退出的思路

    1. 在服务启动时注册自己的ShutdownHook
    2. ShutdownHook在被运行时,首先不接收新的请求,或者告诉调用方重定向到其他节点
    3. 等待当前的执行线程运行完毕,如果五秒后仍在运行,则强制退出

Runtime.addShutdownHook用法的更多相关文章

  1. Runtime.addShutdownHook的用法

    原文出处:http://kim-miao.iteye.com/blog/1662550.感谢作者的无私分享. 一.Runtime.addShutdownHook理解 在看别人的代码时,发现其中有这个方 ...

  2. Java Runtime.exec()用法

    转自:https://www.cnblogs.com/mingforyou/p/3551199.html Java Runtime.exec()的使用 Sun的doc里其实说明还有其他的用法: exe ...

  3. 利用 java.lang.Runtime.addShutdownHook() 钩子程序,保证java程序安全退出

    以前在开发时只知道依靠数据库事务来保证程序关闭时数据的完整性. 但有些时候一个业务上要求的原子操作,不一定只包括数据库,比如外部接口或者消息队列.此时数据库事务就无能为力了. 这时我们可以依靠java ...

  4. Runtime.addShutdownHook()(译)

    序言: 每一个Java程序都可以为JVM增加一个关闭钩子.JVM将在关闭之前执行关闭钩子中的指令. 问题: 一个程序可能需要在退出前执行一些指令.程序可能由于下列原因而退出: 所有的线程已经执行完毕 ...

  5. 【转】RunTime.getRunTime().addShutdownHook用法

    Runtime.getRuntime().addShutdownHook(shutdownHook); 这个方法的含义说明: 这个方法的意思就是在jvm中增加一个关闭的钩子,当jvm关闭的时候,会执行 ...

  6. RunTime.getRunTime().addShutdownHook用法

    今天在阅读Tomcat源码的时候,catalina这个类中使用了下边的代码,不是很了解,所以google了一下,然后测试下方法,Tomcat中的相关代码如下: Runtime.getRuntime() ...

  7. Java中RunTime.getRunTime().addShutdownHook用法

    今天在阅读Tomcat源码的时候,catalina这个类中使用了下边的代码,不是很了解,所以google了一下,然后测试下方法,Tomcat中的相关代码如下: Runtime.getRuntime() ...

  8. Runtime的用法

    public class RuntimeTest { public static void main(String[] args) { Runtime run =Runtime.getRuntime( ...

  9. IOS Runtime的用法

    什么是runtime? 1> runtime是一套底层的C语言API(包含很多强大实用的C语言数据类型.C语言函数)2> 实际上,平时我们编写的OC代码,底层都是基于runtime实现的* ...

随机推荐

  1. 15-Git使用语法

    Git命令 版本库的创建 方法一:使用git bash 1. 在当当前要加创建版本库的文件夹右键使用GitBash 创建仓库执行命令: $ git init 方法二:使用TortoiseGit 2. ...

  2. Params:params 关键字可以指定在参数数目可变处采用参数的方法参数。

    Params:params 关键字可以指定在参数数目可变处采用参数的方法参数. 注意点: 1.一个方法中只能使用一个params来声明不定长参数数组: 2.params参数数组只能放在已定义参数后面 ...

  3. GPU 版 TensorFlow failed to create cublas handle: CUBLAS_STATUS_ALLOC_FAILED

    原因: 使用 GPU 版 TensorFlow ,并且在显卡高占用率的情况下(比如玩游戏)训练模型,要注意在初始化 Session 的时候为其分配固定数量的显存,否则可能会在开始训练的时候直接报错退出 ...

  4. 利用VS Code在Azure上构建部署静态页面

    0x00 前言 前一段时间,我找到了Jendrik Illner的个人网站.除了那里的精彩文章,网站的主题也吸引了我的注意力,而且我发现该网站的主题采用了Hugo的Academic主题. 然后,我认为 ...

  5. css—动画(transform, transition, animation)

    transform 静态属性,一旦写进style里面,会立即显示作用,无任何变化过程.(类似于left, right, top, bottom这类属性) 主要用来做元素的变形 改变元素样式的属性主要有 ...

  6. [Wpf学习] 2.代码导入Xaml

    废话不说,直接上代码 using System.ComponentModel; using System.Runtime.CompilerServices; using System.Windows; ...

  7. win10安装两个不同版本的mysql(mysql5.7和mysql-8.0.19)

    win10中安装mysql5.7后,安装mysql-8.0.19 在D:\mysql-8.0.19-winx64目录下创建一个my.ini文件 [mysqld] # 设置3307端口 port # 设 ...

  8. ORACLE ANALYZE使用小结

      ANALYZE的介绍     使用ANALYZE可以收集或删除对象的统计信息.验证对象的结构.标识表或cluster中的行迁移/行链接信息等.官方文档关于ANALYZE功能介绍如下: ·      ...

  9. 有哪些「看似复杂,实则简单」的 PS 技巧?

    Mac版ps2019哪里有?本次主要以组合键为主,PS中隐藏功能都是通过这些“组合技”启动的,据统计熟练地使用一系列组合技会让你的效率提升30%(纯属虚构).其中一些比较难理解的我都制作了GIF动态图 ...

  10. com.google.gson json字符串的序列化与反序列化

    经常做协议的时候用到json,个人习惯是定义协议文档,很少在这中场景中定义类,使用对象. 这里使用一个人物有名字,性别,有一个物品列表做个简单示例记录. 序列化 JsonObject jo=new J ...