0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

京东云 来源:京东物流 崔冬冬 作者:京东物流 崔冬冬 2024-12-19 10:36 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

作者:京东物流 崔冬冬

一、先提出一个问题

我们如果在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() {
            @Override
            public 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() {
            @Override
            public 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 ) 写代码时候控制执行逻辑、时长

kill -9 命令 强制退出

六、扩展

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

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

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

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

七、总结

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

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

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

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • JAVA
    +关注

    关注

    20

    文章

    2997

    浏览量

    115696
  • JVM
    JVM
    +关注

    关注

    0

    文章

    161

    浏览量

    12957
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    电能质量在线监测装置的报警功能可以关闭吗?

    电能质量在线监测装置的报警功能 能否关闭及如何关闭,取决于装置的设计、功能等级和具体配置 。以下是详细分析: 一、核心结论:报警功能可部分关闭,但安全相关报警通常不可禁用 多数装置支持选择性
    的头像 发表于 11-05 13:38 160次阅读

    Arm Neoverse CPU上大代码量Java应用的性能测试

    Java 是互联网领域广泛使用的编程语言。Java 应用的一些特性使其性能表现与提前编译的原生应用(例如 C 程序)大相径庭。由于 Java 字节码无法直接在 CPU 上执行,因此通常运行时在
    的头像 发表于 11-05 11:25 382次阅读
    Arm Neoverse CPU上大代码量<b class='flag-5'>Java</b>应用的性能测试

    交易关闭自动处理接口

    ​  在电商、支付系统或任何交易密集型应用中,交易关闭(如用户取消订单、支付超时或系统异常)是常见事件。手动处理这些事件效率低下且易出错,因此开发一个自动处理接口至关重要。本文将从需求分析、工作原理
    的头像 发表于 10-17 14:25 254次阅读
    交易<b class='flag-5'>关闭</b>自动处理接口

    Java效率提升指南:5个Java工具选型建议及Perforce JRebel和XRebel介绍

    企业级Java环境越来越复杂,真正的破局点,可能不在“人”,而在于“工具”。5个实用建议,帮你理清Java工具的选型思路。
    的头像 发表于 09-11 13:59 923次阅读
    <b class='flag-5'>Java</b>效率提升指南:5个<b class='flag-5'>Java</b>工具选型建议及Perforce JRebel和XRebel介绍

    EtherCAT运动控制卡应用开发教程之Java

    运动控制卡的Java开发及DLL调用
    的头像 发表于 06-13 14:29 633次阅读
    EtherCAT运动控制卡应用开发教程之<b class='flag-5'>Java</b>

    Java开发者必备的效率工具——Perforce JRebel是什么?为什么很多Java开发者在用?

    Perforce JRebel是一款Java开发效率工具,旨在帮助java开发人员更快地编写更好的应用程序。JRebel可即时重新加载对代码的修改,无需重启或重新部署应用程序,就能让开发者即时看到代码更改的效果,从而缩短开发、调试和测试周期,大大提升开发效率。
    的头像 发表于 04-27 13:44 655次阅读
    <b class='flag-5'>Java</b>开发者必备的效率工具——Perforce JRebel是什么?为什么很多<b class='flag-5'>Java</b>开发者在用?

    推荐!如何优雅地摆好PCB丝印?

    很多画PCB的人,会认为丝印不影响电路的性能,所以,对丝印并不重视。但是,对于一个专业的硬件工程师来说,必须重视这些细节。 下面介绍如何优雅地弄好PCB丝印。 1 摆放的位置 一般来说,电阻、电容
    发表于 04-08 14:59

    我只会Java,凭什么不能玩转树莓派?GPIO操控竟比C++更优雅~

    导语当全球开发者默认将Python视为树莓派的"母语"时,一个颠覆认知的工具链正在Java开发者群体中口口相传——Pi4J让Java代码直接操控GPIO、I2C、SPI等硬件接口
    的头像 发表于 03-25 09:21 872次阅读
    我只会<b class='flag-5'>Java</b>,凭什么不能玩转树莓派?GPIO操控竟比C++更<b class='flag-5'>优雅</b>~

    Java的SPI机制详解

    作者:京东物流 杨苇苇 1.SPI简介 SPI(Service Provicer Interface)是Java语言提供的一种接口发现机制,用来实现接口和接口实现的解耦。简单来说,就是系统只需要定义
    的头像 发表于 03-05 11:35 1122次阅读
    <b class='flag-5'>Java</b>的SPI机制详解

    Java应用OOM问题的排查过程

    导读 本文记录最近一例Java应用OOM问题的排查过程,希望可以给遇到类似问题的同学提供参考。 前言:此文记录最近一例Java应用OOM问题的排查过程,希望可以给遇到类似问题的同学提供参考。在本地
    的头像 发表于 02-12 11:15 1075次阅读
    <b class='flag-5'>Java</b>应用OOM问题的排查过程

    hyper v关闭关闭Hyper-V的原因有哪些?

    整合等。但在某些情况下,用户可能需要关闭Hyper-V。接下来,我们将深入探讨关闭Hyper-V的原因。    关闭Hyper-V的原因    提升系统性能:运行Hyper-V会占用一定的系统资源,包括CPU、内存和磁盘空间等。
    的头像 发表于 02-05 14:29 2723次阅读
    hyper v<b class='flag-5'>关闭</b>,<b class='flag-5'>关闭</b>Hyper-V的原因有哪些?

    Spire.XLS for Android via Java组件说明

    Spire.XLS for Android via Java 是一款专业的 Android Excel 组件,用于在 Android 手机应用程序中创建、操作和转换 Excel 工作表,并且运行环境
    的头像 发表于 01-24 12:16 824次阅读
    Spire.XLS for Android via <b class='flag-5'>Java</b>组件说明

    联想电脑如何关闭云存储,联想电脑如何使用才能关闭云存储

        在教育领域,云电脑的应用不仅提高了教学效率,还为学生提供了更加丰富的学习资源和互动体验,推动了教育的现代化发展。今天就为大家介绍联想电脑如何使用才能关闭云存储。    要关闭联想电脑上的云
    的头像 发表于 01-08 14:50 3283次阅读
    联想电脑如何<b class='flag-5'>关闭</b>云存储,联想电脑如何使用才能<b class='flag-5'>关闭</b>云存储

    华为云 Flexus X 实例下的场景体验——小企业必备——JAVA 环境搭建——保姆级教学

    前言 上次我们使用的是 Ubuntu 来操作的,这里跑的服务器多的还是 Huawei Cloud EulerOS,所以我们还原到基础镜像上做环境架设,此次我们来架设 java 的基础运行环境,是能
    的头像 发表于 01-07 17:05 765次阅读
    华为云 Flexus X 实例下的场景体验——小企业必备——<b class='flag-5'>JAVA</b> 环境搭建——保姆级教学

    SSM框架在Java开发中的应用 如何使用SSM进行web开发

    SSM框架,即Spring、SpringMVC和MyBatis的整合,是Java Web开发中常用的技术栈。它通过分层架构,实现了视图、控制、业务逻辑和数据访问的分离,提高了代码的可维护性和可扩展性
    的头像 发表于 12-16 17:28 2150次阅读