当前位置: 首页 > news >正文

java小知识-ShutdownHook(优雅关闭)

一、先提出一个问题

我们如果在JVM退出的时候做一些事情,比如关闭远程链接,怎么实现呢?

二、ShutdownHook简介

java里有个方法Runtime.getRuntime#addShutdownHook,是否了解呢?

ShutdownHook是什么意思呢,看单词解释“关闭钩子”,addShutdownHook就是添加一个关闭钩子,这个钩子是做什么的呢?能否解决上面的问题?

1、RunTime类

先看一下看源码RunTime#addShutdownHook方法与解释。

1.1 方法解释

核心意思,在Java虚拟机在关闭时会触发一些自己添加的事件。

Registers a new virtual-machine shutdown hook.
The Java virtual machine shuts down in response to two kinds of events:
The program exits normally, when the last non-daemon thread exits or when the exit (equivalently, System.exit) method is invoked, or
The virtual machine is terminated in response to a user interrupt, such as typing ^C, or a system-wide event, such as user logoff or system shutdown.
A shutdown hook is simply an initialized but unstarted thread. When the virtual machine begins its shutdown sequence it will start all registered shutdown hooks in some unspecified order and let them run concurrently. 
When all the hooks have finished it will then halt. Note that daemon threads will continue to run during the shutdown sequence, as will non-daemon threads if shutdown was initiated by invoking the exit method.

1.2 方法源码

  public void addShutdownHook(Thread hook) {@SuppressWarnings("removal")SecurityManager sm = System.getSecurityManager();if (sm != null) {sm.checkPermission(new RuntimePermission("shutdownHooks"));}ApplicationShutdownHooks.add(hook);}

方法内部调用了ApplicationShutdownHooks#add,我们继续往下看。

2、ApplicationShutdownHooks类

2.1 添加钩子

private static IdentityHashMap<Thread, Thread> hooks;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);}

我们添加了一个钩子,这个钩子是个线程,这个线程怎么执行的呢? 继续看一下此类中的runHooks。

2.2 执行钩子


static void runHooks() {Collection<Thread> threads;synchronized(ApplicationShutdownHooks.class) {threads = hooks.keySet();hooks = null;}for (Thread hook : threads) {hook.start();}for (Thread hook : threads) {while (true) {try {hook.join();break;} catch (InterruptedException ignored) {}}}}

执行runHooks的时候,会启动所有的hook线程,什么时候调用runHooks方法的呢?

2.3 执行时机

为什么在系统退出的时候会执行添加的hook呢?我们看一下正常的退出操作System#exit方法。

1) 类调用层级

System->Runtime->Shutdown->ApplicationShutdownHooks

2) 方法调用

系统退出入口:System#exit

步骤 1-->System#exit

步骤 2-->Runtime#exit;

步骤 3--> Shutdown#exit

步骤 4--> Shutdown#runHooks

步骤 5--> ApplicationShutdownHooks#runHooks

步骤 6-->启动添加的hook线程

3) 补充一下

为什么步骤4会调用到步骤5呢?

可以看一下ApplicationShutdownHooks的构造函数,在创建的时候,封装了runHooks方法,放到了Shutdown的钩子集合里。

如此形成闭环,在系统正常退出的时候,最终执行我们添加的hook。

三、举个例子

了解了基本原理,我们看一下怎么使用的

    public static void main(String[] args) throws InterruptedException {Thread thread = new Thread() {@Overridepublic void run() {System.out.println("等等我");}};Runtime.getRuntime().addShutdownHook(thread);System.out.println("程序关闭"); }输出:程序关闭等等我

可以看到,在JVM退出的时候调用,执行了此线程,我们开发中,哪些场景可以使用呢?

四、应用场景

关闭链接、线程、资源释放、记录执行状态等。

五、风险点

1、长时间等待

如果添加的hook线程长时间执行,我们的退出命令会一直等待,为什么呢?

举个例子,我们在执行的时候sleep一下

  public static void main(String[] args) throws InterruptedException {Thread thread = new Thread() {@Overridepublic void run() {try {Thread.sleep(1000*300);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(new Date()+" 等我5分钟");}};Runtime.getRuntime().addShutdownHook(thread);System.out.println(new Date()+" 程序关闭");}
输出:
Tue Nov 12 17:37:38 CST 2024 程序关闭
Tue Nov 12 17:42:38 CST 2024 等我5分钟

2、原因

JVM在退出的时候会调用runHooks方法,看一下上面的方法java.lang.ApplicationShutdownHooks#runHooks方法。

关键字 hook.join(); 主线程会等待子线程执行完成。

如果程序一直执行,不能退出怎么办?

3、解决方案

1 ) 写代码时候控制执行逻辑、时长

2) kill -9 命令 强制退出

六、扩展

1、Runtime.getRuntime#addShutdownHook是面向开发者的

ApplicationShutdownHook#add、Shutdown#add我们都不能直接使用。

2、许多中间件框架也利用addShutdownHook来实现资源回收、清理等操作

比如Spring框架中,使用了ShutdownHook注册,我们常用的@PreDestroy在Bean销毁前执行一些操作,也是借助其回调的。

七、总结

1、本文简单介绍了一下ShutdownHook使用、原理、风险点。

2、我们工作中可以自己注册ShutdownHook,主动释放一些资源,降低风险。

3、小知识分享,不足之处欢迎大家指正,关于java里的知识点也欢迎大家讨论分享。

http://www.jsqmd.com/news/26360/

相关文章:

  • ARM - RD-N2 (cfg1 ... cfgn) software stack compiling environment setup walkthrough - ENGINEER
  • 2025 年山东自卸半挂车,济宁自卸半挂车,平推式自卸半挂车厂家最新推荐,产能、专利、环保三维数据透视!
  • 2025年防爆不锈钢穿线盒制造企业权威推荐榜单:防爆铸钢接线盒/防爆铸钢穿线盒/防爆弯头铸钢4分6分源头厂家精选
  • 利驰软件与人民电器集团上海有限公司开启能源数字化新篇章!
  • 2025年热门的JN30高压均质机TOP品牌厂家排行榜
  • 2025年纸浆压滤机厂商权威推荐榜单:造纸厂压滤机/造纸污泥压滤机/挤浆机源头厂家精选
  • 2025年下半年国内最热门GEO/AI搜索优化/搜荐推广/短视频矩阵系统/无人直播系统/数字人系统/智能体直播厂家摘星搜荐:揭秘领先品牌的创新技术与市场表现
  • 2025 年西安月子会所最新推荐榜,技术实力与市场口碑深度解析月子会所月子餐 / 高新月子会所推荐
  • 2025年10月最新公布GEO/AI搜索优化/搜荐推广/短视频矩阵系统/无人直播系统/数字人系统/智能体直播厂家:摘星AI人工智能揭秘下一代智能营销技术趋势
  • 2025 年木托盘源头厂家最新推荐榜,聚焦技术实力与市场口碑深度解析,助力企业精准采购免熏蒸木托盘/熏蒸托盘/熏蒸木托盘公司推荐
  • 2025年靠谱的卡车刹车盘厂家实力及用户口碑排行榜
  • HarmonyOS实战项目:开发一个分布式新闻阅读客户端
  • 【渲染优化】动态调整虚拟列表刷新率:让代码学会偷懒
  • HarmonyOS分布式媒体播放器——跨设备音视频无缝流转
  • HarmonyOS实战项目:构建一个跨设备的Todo清单应用(上)
  • 主语 + 系动词 + 表语句型解析
  • HarmonyOS状态管理入门:@State与@Link装饰器的原理与实践
  • HarmonyOS布局艺术:Flex、Stack、Grid等容器组件的使用技巧
  • 有什么简单好用的开源 AI 智能体平台?试了 5 个主流项目,聊聊真实体验
  • RecyclerView使用-涂鸦智能App的首页和添加效果-从0到1详细过程
  • ArkUI声明式开发范式:构建响应式用户界面
  • AI模型介绍
  • 2025年靠谱的珍珠棉TOP实力厂家推荐榜
  • jmeter 创建100个现场组,每个线程组里面有1个http请求,并针对每个http请求响应头进行断言
  • 3步法让小程序体验更高级:兰亭妙微分享小团队也能做到的设计优化技巧
  • Redis key 消失之谜
  • Blazor 感觉回到了ASP时代?
  • 2025年靠谱的FFU龙骨优质厂家推荐榜单
  • 2025年比较好的三维调节阻尼托底轨TOP品牌厂家排行榜
  • 父子组件联动出现问题的一个bug记录