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
    +关注

    关注

    19

    文章

    2966

    浏览量

    104700
  • JVM
    JVM
    +关注

    关注

    0

    文章

    158

    浏览量

    12220
收藏 人收藏

    评论

    相关推荐

    Java 23功能介绍

    Java 23 包含全新和更新的 Java 语言功能、核心 API 以及 JVM,同时适合新的 Java 开发者和高级开发者。从 IntelliJ IDEA 2024.2 开始已支持 Java
    的头像 发表于 12-04 10:02 192次阅读
    <b class='flag-5'>Java</b> 23功能介绍

    java知识-纳秒

    作者:京东物流 崔冬冬 一、System.nanoTime() java中,有这么一个方法 System.nanoTime() ,你用过吗? 二、与System.currentTimeMillis
    的头像 发表于 11-26 11:11 117次阅读

    Java集合API的改进介绍

    解答这些问题。 我们将逐步学习 Java 集合类的优化过程,并按版本逐一对比分析。主要讨论的焦点将包括 JDK 1.0、1.2、1.4、1.5、1.6、1.8、9、10、11 和 21 版本的 Java 集合功能 Java 集合
    的头像 发表于 11-22 11:12 171次阅读
    <b class='flag-5'>Java</b>集合API的改进介绍

    基于Java的工具Power Stage Designer

    电子发烧友网站提供《基于Java的工具Power Stage Designer.pdf》资料免费下载
    发表于 11-14 16:01 2次下载
    基于<b class='flag-5'>Java</b>的工具Power Stage Designer

    Java中时间戳的使用

    Java中时间戳的使用
    的头像 发表于 11-06 16:04 188次阅读
    <b class='flag-5'>Java</b>中时间戳的使用

    C语言与Java语言的对比

    C语言和Java语言都是当前编程领域中的重要成员,它们各自具有独特的优势和特点,适用于不同的应用场景。以下将从语法特性、内存管理、跨平台性、性能、应用领域等多个方面对C语言和Java语言进行详细对比。
    的头像 发表于 10-29 17:31 315次阅读

    java反编译能拿到源码吗

    Java反编译是一种将编译后的Java字节码(.class文件)转换回Java源代码的过程。虽然反编译可以帮助理解代码的逻辑和结构,但它并不总是能完美地还原原始源代码。反编译工具通常会产生与原始代码
    的头像 发表于 09-02 11:03 941次阅读

    【转型必看】Java到AI,程序员的逆袭秘籍,转行人工智能不再是梦!

    人工智能,转型的优势,薪资对比,以及转型所需的知识和学习路线等。01Java开发者能否转型人工智能?答案是肯定的。Java作为一种广泛使用的编程语言,拥有强大的生
    的头像 发表于 07-31 14:42 1037次阅读
    【转型必看】<b class='flag-5'>Java</b>到AI,程序员的逆袭秘籍,转行人工智能不再是梦!

    华纳云:java web和java有什么区别java web和java有什么区别

    Java Web和Java是两个不同的概念,它们在功能、用途和实现方式上存在一些区别,下面将详细介绍它们之间的区别。 1. 功能和用途: – Java是一种编程语言,它提供了一种用于开发各种应用程序
    的头像 发表于 07-16 13:35 783次阅读
    华纳云:<b class='flag-5'>java</b> web和<b class='flag-5'>java</b>有什么区别<b class='flag-5'>java</b> web和<b class='flag-5'>java</b>有什么区别

    华为云开发者桌面全新发布 CodeArts IDE for Python,极致优雅云原生开发体验

    Python 编码体验。 Python 是一种编程语言,广泛用于 Web 应用程序、软件开发、数据科学和机器学习 (ML)。Python 以其优雅的语法、动态解释性、丰富的标准库、极高的开发效率深受全球开发者
    的头像 发表于 05-10 00:27 1233次阅读
    华为云开发者桌面全新发布 CodeArts IDE for Python,极致<b class='flag-5'>优雅</b>云原生开发体验

    已经安装了Java,且依然提示安装Java是为什么?

    我已经在机器上安装了最新版的 Java 10,打开 Cube 却得到要求安装 Java 1.7.0_45 的提示。何解?Eclipse CDT 依赖 Java,不可卸载重装。
    发表于 04-26 06:23

    java实现多线程的几种方式

    Java实现多线程的几种方式 多线程是指程序中包含了两个或以上的线程,每个线程都可以并行执行不同的任务或操作。Java中的多线程可以提高程序的效率和性能,使得程序可以同时处理多个任务。 Java提供
    的头像 发表于 03-14 16:55 686次阅读

    实用小知识:如何检测油箱盖是否关闭

    汽油箱和加注口周围被认为是高度危险的易爆区域,存在引发火灾的风险。车辆操作员或维修人员容易忘记关闭油箱盖,而直接从油箱中偷盗汽油的现象也在增加。为了解决这些问题,设计师现在打算采用干簧传感器。这种
    的头像 发表于 02-26 11:25 1137次阅读
    实用小<b class='flag-5'>知识</b>:如何检测油箱盖是否<b class='flag-5'>关闭</b>?

    优雅停机是什么?SpringBoot+Nacos+k8s实现优雅停机

    优雅停机是什么?网上说的优雅下线、无损下线,都是一个意思。
    的头像 发表于 02-20 10:00 2025次阅读
    <b class='flag-5'>优雅</b>停机是什么?SpringBoot+Nacos+k8s实现<b class='flag-5'>优雅</b>停机

    Oracle 2024年Java发展蓝图分析

    Oracle 的 Java 开发者布道师 Nicolai Parlog 于近日发布一段视频,介绍了 2024 年的 Java 工作规划。
    的头像 发表于 01-26 14:27 1326次阅读