【Java基础】JVM关闭回调函数(ShutdownHook)的应用场景

news2024/11/17 9:52:07

文章目录

    • 一.ShutdownHook介绍
    • 二.ShutdownHook被调用场景
    • 三.ShutdownHook如何使用
    • 四.ShutdownHook实践

一.ShutdownHook介绍

  • ShutdownHook就是一个简单的 已初始化 但是 未启动 的 线程 。当虚拟机开始关闭时,它将会调用所有已注册ShutdownHook的回调函数,这些回调函数执行是并发的,执行顺序是不确定的

    • 作用:JVM退出时执行的业务逻辑( 注意:ShutdownHook方法参数必须是Thread的子类,由此得知,ShutdownHook是异步执行的。
      • 添加:Runtime.getRuntime(). addShutdownHook(Thread var1)
      • 移除:Runtime.getRuntime().removeShutdownHook(this.shutdownHookThread)
  • 需要注意的是,在ShutdownHook里执行的操作应当是不太耗时的。因为在用户注销或者操作系统关机导致的JVM shutdown的例子中,系统只会预留有限的时间给未完成的工作,超时之后还是会强制关闭。

二.ShutdownHook被调用场景

  • 程序正常退出
  • 程序调用 System.exit() 退出
  • 终端使用 Ctrl+C 中断程序
  • 程序抛出异常导致程序退出,例如 OOM,数组越界等异常
  • 系统事件,例如用户注销或关闭系统
  • 使用 Kill pid 命令杀掉进程,注意使用 kill -9 pid 强制杀掉不会触发执行钩子

三.ShutdownHook如何使用

调用java.lang.Runtime这个类的addShutdownHook(Thread hook)方法即可注册一个ShutdownHook,然后在Thread中定义需要在system exit时进行的操作。如下:

Runtime.getRuntime().addShutdownHook(new Thread(() -> 
    System.out.println("Do something in ShutdownHook")
));

测试例子

  • 首先,注册了一个ShutdownHook。
    • 然后,系统Sleep 3秒,模拟进行某些操作。
      • 然后,调用一个空的List,抛出异常,准备结束程序。
        • 在程序将要结束的时候,执行ShutdownHook中的内容。
public static void main(String[] args)
{
    // register ShutdownHook
    Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println("Do something in ShutdownHook")));

    // sleep for some time
    try {
        for (int i=0; i<3; i++) {
            System.out.println("Count: " + i + "...");
            TimeUnit.MILLISECONDS.sleep(1000);
        }
        List nullList = new ArrayList<>();
        System.out.println("Trying to print null list's first element: " + nullList.get(0).toString());
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println("Ready to exit.");
    System.exit(0);
}

结果如下:

Count: 0...
Count: 1...
Count: 2...
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
    at java.util.ArrayList.rangeCheck(ArrayList.java:653)
    at java.util.ArrayList.get(ArrayList.java:429)
    at HookTest.main(HookTest.java:18)
Do something in ShutdownHook

Process finished with exit code 1

需要注意的点

  • 当System.exit之后,当ShutdownHook开始执行时,其他的线程还是会继续执行
  • 应当保证ShutdownHook的线程安全。
    • 在使用多个ShutdownHook时一定要特别小心,保证其调用的服务不会被其他Hook影响。否则会出现当前Hook所依赖的服务被另外一个Hook终止了的情况。

四.ShutdownHook实践

例如,我们程序自定义了一个线程池,用来接收和处理任务。如果程序突然崩溃异常退出,这时线程池的所有任务有可能还未处理完成,如果不处理完程序就直接退出,可能会导致数据丢失,业务异常等重要问题。这时钩子就派上用场了。

 import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
 
public class ShutdownHookDemo {
    // 线程池
    private static ExecutorService executorService = Executors.newFixedThreadPool();
 
    static {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            System.out.println("开始执行钩子方法...");
            // 关闭线程池
            executorService.shutdown();
            try {
                // 等待秒
                System.out.println(executorService.awaitTermination(, TimeUnit.SECONDS));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("结束执行钩子方法...");
        }));
    }
 
    public static void main(String[] args) throws InterruptedException {
        System.out.println("程序开始启动...");
        // 向线程池添加个任务
        for (int i =; i < 10; i++) {
            Thread.sleep();
            final int finalI = i;
            executorService.execute(() -> {
                try {
                    Thread.sleep();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Task " + finalI + " execute...");
            });
            System.out.println("Task " + finalI + " is in thread pool...");
        }
    }
} 

在命令行窗口中运行程序,在10个任务都提交到线程池之后,任务都还未处理完成之前,使用Ctrl+C中断程序,最终在虚拟机关闭之前,调用了关闭回调函数,关闭线程池,并且等待60秒让所有任务执行完成。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1411043.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

x-cmd pkg | sqlite3 - 轻量级的嵌入式关系型数据库

目录 简介首次用户 技术特点竞品和相关产品sqlite 与 x-cmd进一步阅读 简介 sqlite3 是一个轻量级的文件数据库&#xff0c;体积非常小&#xff0c;提供简单优雅而功能强大的 sql 化的数据查询。 通常情况下&#xff0c;sqlite 指的是 SQLite 2.x 版本&#xff0c;而 sqlite3 …

【WPF.NET开发】WPF 中的 Layout

本文内容 元素边界框布局系统测量和排列子元素面板元素和自定义布局行为布局性能注意事项子像素渲染和布局舍入 本主题介绍 Windows Presentation Foundation (WPF) 布局系统。 了解布局计算发生的方式和时间对于在 WPF 中创建用户界面非常重要。 1、元素边界框 在 WPF 中构…

unity学习笔记----游戏练习07

一、僵尸攻击和植物的掉血和销毁 当僵尸接触到植物开始攻击时会持续削减植物的血量&#xff0c;当植物血量为零时就销毁当前植物。 在plantManager中&#xff0c; 为植物添加一个血量HP 100&#xff0c; public int HP 100; 在写一个减少血量的方法&#xff0c;来减少血…

安全防御第三次作业

作业&#xff1a;拓扑图及要求如下图 注&#xff1a;server1是ftp服务器&#xff0c;server2是http服务器 lsw1&#xff1a; 其中g0/0/0口为trunk 实现 1&#xff0c;生产区在工作时间内可以访问服务器区&#xff0c;仅可以访问http服务器 验证&#xff1a; 2&#xff0c;办公…

代码随想录算法训练营第二十七天|455.分发饼干 , 376. 摆动序列 , 53. 最大子序和

455.分发饼干 代码随想录 class Solution {public int findContentChildren(int[] g, int[] s) {int ans 0;Arrays.sort(g);Arrays.sort(s);int start s.length - 1;for (int i g.length - 1; i >0; i--) {if (start > 0 && s[start] > g[i]) {ans;start…

精要图示:园区金融数字化服务蓝图,以园区为支点推动信贷业务增长

作为企业集聚地&#xff0c;园区已然成为银行业夯实客群基础的重要切口&#xff0c;各大行陆续围绕园区场景创新金融产品&#xff0c;以期抢跑园区金融新赛道、把握新增量。 启信慧眼首推一站式【园区金融】数字化服务方案&#xff0c;该方案同时支持启信天元私有化部署&#x…

idea 打包跳过测试

IDEA操作 点击蓝色的小球 手动命令 mvn clean package -Dmaven.test.skiptrue

水波浪标题

上图效果要先复制第13次修改的备忘录&#xff0c;再另外保存下面的代码&#xff1a; <!DOCTYPE html> <html lang"zh"> <a class"a-href a-h">水波浪标题</a> <style>.h1-div {/* 隐藏 */display: none;}h1 {display: inli…

【干货】【常用电子元器件介绍】【电阻】(二)--敏感电阻器

声明&#xff1a;本人水平有限&#xff0c;博客可能存在部分错误的地方&#xff0c;请广大读者谅解并向本人反馈错误。   电子电路中除了采用普通电阻器外&#xff0c;还有一些敏感电阻器&#xff08;如热敏电阻器、压敏电阻器、光敏电阻器等&#xff09;也被广泛地应用。然而…

直播核心岗位基础内容

一.直播间核心岗位 1.直播间前端岗位 前端岗位分工 &#xff08;1&#xff09;主播岗位职责 &#xff08;2&#xff09;场控岗位职责 &#xff08;3&#xff09;助理岗位职责 中端岗位分工 &#xff08;1&#xff09;运营岗位职责 &#xff08;2&#xff09;中控岗位职责 …

C# 使用AutoMapper实现类映射

写在前面 AutoMapper是一个用于.NET中简化类之间的映射的扩展库&#xff1b;可以在执行对象映射的过程&#xff0c;省去的繁琐转换代码&#xff0c;实现了对DTO的快速装配&#xff0c;有效的减少了代码量。 通过NuGet安装&#xff0c;AutoMapper&#xff0c; 由于本例用到了D…

【Unity】粒子贴图异常白边问题

从PS制作的黑底&#xff0c;白光的贴图。放入Unity粒子中&#xff0c;拉远看会有很严重的白边&#xff0c;像马赛克一样。 材质使用&#xff1a;Mobile/Particles/Additive 经测试只使用一张黑色的图片&#xff0c;也会有白边。 解决方案&#xff1a; 关闭黑色底&#xf…

RX4901CE (RTC模块)

RX4901CE是一个集成了32.768 kHz数字温度补偿晶体振荡器(DTCXO)的RTC模块。高稳定性&#xff0c;低电流消耗&#xff0c;时间戳功能&#xff0c;当外部或内部事件发生时&#xff0c;可以记录多达32个日期和时间&#xff0c;以及基本的RTC功能&#xff0c;如时间和日历&#xff…

什么是servlet

什么是servlet 什么是servlet Servlet&#xff08;Server Applet&#xff09;是 Java Servlet 的简称&#xff0c;称为小服务程序或服务连接器&#xff0c;用 Java 编写的服务器端程序&#xff0c;具有独立于平台和协议的特性&#xff0c;主要功能在于交互式地浏览和生成数据…

对话泛能网程路:能源产业互联网,行至中程

泛能网的能源产业互联网的标杆价值还不仅于此。其在产业互联之外&#xff0c;也更大的特殊性在于其也更在成为整个碳市场的“辅助运营商”&#xff0c;包括电力、碳等一系列被泛能网帮助企业改造和沉淀的要素资产&#xff0c;都在构成着碳交易市场的未来底层。 这恰是产业互联…

图像处理------调整色调

什么是色调&#xff1f; 色调&#xff0c;在画面上表现思想、感情所使用的色彩和色彩的浓淡。分为暖色调和冷色调。 from cv2 import destroyAllWindows, imread, imshow, waitKey#创建棕褐色色调 def make_sepia(img, factor: int):pixel_h, pixel_v img.shape[0], img.shap…

Vector OJ:电话号码组合 数组中超过一半的数字

目录 1.电话号码组合 2. JZ39 数组中出现次数超过一半的数字 3.删除有序数组中的重复项 1.电话号码组合 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xf…

TensorFlow 深度学习 开发环境搭建 全教程

PyTorch 深度学习 开发环境搭建 全教程 TensorFlow 深度学习 开发环境搭建 全教程 1、指定清华源命令 -i https://pypi.tuna.tsinghua.edu.cn/simple2、conda安装 这是AI开发环境的全家桶&#xff0c;官网下载链接Anaconda | Start Coding Immediately 尽量不要选择太新版本…

勤哲 Excel 服务器2017 V13.0.144 最好用稳定版本,带注册,无限用户,含教程【亲测非常好用】

勤哲EXCEL 服务器 V13.0.144 无限用户 无限数据 非常好用 非常稳定。 Excel服务器是一个面向最终用户的信息系统设计工具与运行平台&#xff0c;它的作用是帮助我们“建立适合需要的管理信息系统&#xff0c;实现管理的信息化”。 谈到管理信息系统&#xff0c;人们很容易联想…

Java笔记(死锁、线程通信、单例模式)

一、死锁 1.概述 死锁 : 死锁是指两个或两个以上的进程在执行过程中&#xff0c;由于竞争资源或者由于彼此通信而造成的一种阻塞的现象&#xff0c;若无外力作用&#xff0c;它们都将无法往下执行。此时称系统处于死锁状态或系统产生了死锁&#xff0c;这些永远在互相等待的进…