Java虚拟机关闭钩子(Shutdown hook)

简介: Shutdown hook是Jvm关闭的钩子,是通过Runtime#addShutdownHook(Thread hook)方法来实现的,根据api是注解可知它就是一系例的已初始化但尚未执行的线程对象。我们可以通过向Jvm注册一个钩子,实现在程序退出时关闭资源、平滑退出的功能。所谓的优雅停机也可以这么搞。

Shutdown hook是什么

Shutdown hook是Jvm关闭的钩子,是通过Runtime#addShutdownHook(Thread hook)方法来实现的,根据api是注解可知它就是一系例的已初始化但尚未执行的线程对象。我们可以通过向Jvm注册一个钩子,实现在程序退出时关闭资源、平滑退出的功能。所谓的优雅停机也可以这么搞。

Jvm关闭的方式

img

程序只有在正常关闭和异常关闭的情况下才会调用钩子函数坐一些扫尾的工作,如果是强制关闭的则不会调用,强制关闭直接无商量终止jvm进程,不给jvm喘息的机会。

使用关闭钩子的注意事项

  • 关闭钩子本质上是一个线程(也称为Hook线程),对于一个JVM中注册的多个关闭钩子它们将会并发执行,所以JVM并不保证它们的执行顺序;由于是并发执行的,那么很可能因为代码不当导致出现竞态条件或死锁等问题,为了避免该问题,强烈建议在一个钩子中执行一系列操作。
  • Hook线程会延迟JVM的关闭时间,这就要求在编写钩子过程中必须要尽可能的减少Hook线程的执行时间,避免hook线程中出现耗时的计算、等待用户I/O等等操作。
  • 关闭钩子执行过程中可能被强制打断,比如在操作系统关机时,操作系统会等待进程停止,等待超时,进程仍未停止,操作系统会强制的杀死该进程,在这类情况下,关闭钩子在执行过程中被强制中止。
  • 在关闭钩子中,不能执行注册、移除钩子的操作,JVM将关闭钩子序列初始化完毕后,不允许再次添加或者移除已经存在的钩子,否则JVM抛出 IllegalStateException。
  • 不能在钩子调用System.exit(),否则卡住JVM的关闭过程,但是可以调用Runtime.halt()。
  • Hook线程中同样会抛出异常,对于未捕捉的异常,线程的默认异常处理器处理该异常,不会影响其他hook线程以及JVM正常退出

简单例子(具体可看源码)

1.业务要关闭的资源

public class StudyResource implements AutoCloseable {

    @Override
    public void close() throws Exception {
        System.out.println("执行项目资源关闭操作");
    }
}

2.自定义钩子

/**
 * @author: lixiaoshuang
 * @create: 2020-11-25 20:48
 **/
public class StudyShtudownHook extends Thread {

    private static final StudyShtudownHook INSTANCE = new StudyShtudownHook();
    /**
     * 需要关闭的钩子集合,可以将项目中的资源关闭操作都放在这里
     */
    private final Set<AutoCloseable> autoCloseableHashSet = new HashSet<>();


    private StudyShtudownHook() {

    }

    public static StudyShtudownHook getInstance() {
        return INSTANCE;
    }


    public void registerAutoCloseable(final AutoCloseable autoCloseable) {
        autoCloseableHashSet.add(autoCloseable);
    }

    @Override
    public void run() {
        this.closeAll();
    }

    @SneakyThrows
    private void closeAll() {
        for (AutoCloseable autoCloseable : autoCloseableHashSet) {
            autoCloseable.close();
        }
    }
}
  1. 向jvm注册钩子
public class JvmHookDemo {

    public static void main(String[] args) throws InterruptedException {
        
        //自己实现的钩子
        StudyShtudownHook instance = StudyShtudownHook.getInstance();
        //将需要关闭的资源放到钩子里
        StudyResource studyResource = new StudyResource();
        instance.registerAutoCloseable(studyResource);

        //向jvm注册钩子
        Runtime.getRuntime().addShutdownHook(instance);

        System.out.println("执行业务逻辑。。。。");
        Thread.sleep(5000);
        System.out.println("业务逻辑处理完毕。。。。");
    }
}

执行这段代码后输出:

执行业务逻辑。。。。

业务逻辑处理完毕。。。。

执行项目资源关闭操作

目录
相关文章
|
2月前
|
存储 算法 安全
Java面试题:Java内存模型及相关知识点深度解析,Java虚拟机的内存结构及各部分作用,详解Java的垃圾回收机制,谈谈你对Java内存溢出(OutOfMemoryError)的理解?
Java面试题:Java内存模型及相关知识点深度解析,Java虚拟机的内存结构及各部分作用,详解Java的垃圾回收机制,谈谈你对Java内存溢出(OutOfMemoryError)的理解?
45 0
|
1月前
|
Java
Java常见JVM虚拟机指令(47个)
Java常见JVM虚拟机指令(47个)
43 3
Java常见JVM虚拟机指令(47个)
|
27天前
|
Java 数据安全/隐私保护 Windows
【Azure Developer】使用Java代码启动Azure VM(虚拟机)
【Azure Developer】使用Java代码启动Azure VM(虚拟机)
|
28天前
|
存储 Java API
【Azure Developer】通过Azure提供的Azue Java JDK 查询虚拟机的CPU使用率和内存使用率
【Azure Developer】通过Azure提供的Azue Java JDK 查询虚拟机的CPU使用率和内存使用率
|
2月前
|
监控 Oracle Java
(一)JVM成神路之初识虚拟机 - 探寻Java虚拟机的前世今生之秘
JVM(Java Virtual Machine)Java虚拟机的概念大家都不陌生,Java之所以可以做到“一次编译,到处运行”的跨平台性,其根本原因就在于JVM。JVM是建立在操作系统(OS)之上的,Java虚拟机屏蔽了开发人员与操作系统的直接接触,我们在通过Java编写程序时,只需要负责编写Java代码即可,关于具体的执行则会由JVM加载字节码后翻译成机械指令交给OS执行。
|
2月前
|
存储 Ubuntu Java
【Linux】已解决:Ubuntu虚拟机安装Java/JDK
【Linux】已解决:Ubuntu虚拟机安装Java/JDK
75 1
|
2月前
|
监控 算法 Java
深入理解Java虚拟机:内存管理与性能优化
在Java的世界里,虚拟机(JVM)是幕后的守护者,它默默地支撑着每一个字节码的运行。本文将揭开JVM的神秘面纱,探讨其内存管理机制及如何通过调优提升应用性能。从堆内存的分配到垃圾回收的策略,再到实践中的性能监控与调优技巧,我们将一同走进JVM的内部世界,学习如何让我们的Java程序跑得更快、更稳。
|
3月前
|
Java API Maven
使用Java Libvirt API 访问虚拟机信息
使用Java Libvirt API 访问虚拟机信息
|
2月前
|
Java
Java演进问题之单个虚拟机的最大线程数量一般会设置到200至400条如何解决
Java演进问题之单个虚拟机的最大线程数量一般会设置到200至400条如何解决
|
2月前
|
存储 监控 算法
探索Java虚拟机:深入理解JVM内存模型和垃圾回收机制
在Java的世界中,JVM是核心所在,它不仅承载着代码的运行,还管理着内存资源。本文将带你深入了解JVM的内存模型和垃圾回收机制,通过具体数据与案例分析,揭示它们对Java应用性能的影响,并探讨如何优化JVM配置以提升效率。