Java虚拟机ShutdownHooks

Java虚拟机为开发人员提供了一个回调入口,开发人员通过这个回调入口,向Java虚拟机注册任意一段代码,让Java虚拟机在将要结束运行之前,执行这段代码。这个机制通常被用来做一些资源的清理工作,tomcat容器源码中就有用到这个机制,现在对这个机制做一个介绍。


demo

public static void main(String[] args) {
    Runtime.getRuntime().addShutdownHook(new Thread(){
        @Override
        public void run() {
            System.out.println("The hook is executing");
        }
    });

    System.out.println("The application is going to be stopped");
}

但是使用Shutdown Hook时,会有一些注意的地方:

  • 在某些情况下向JVM注册的hooks不会被执行
    JVM并不保证这些hooks一定会被执行,hooks是否会被执行受系统内部及外部因素影响。

    1. JVM遇到严重的内部错误的时候
    2. 用户通过操作系统向Java虚拟机进程发送SIGKILL,要求操作系统立即停止虚拟机进程时
    3. 调用Runtime.halt()停止虚拟机执行

    只有当JVM正常退出时,hooks才会被执行,应用程序抛出的运行时异常,以及JVM抛出的错误(Error)不会影响hook的执行。

  • Shutdown Hook处于执行状态时,仍有可能被强制停止
    一旦hooks启动之后,仍然可能由于各种原因被停止,需要注意的是,不能在hooks中进行一些非常耗时的操作,以及资源申请操作,因为这样会造成严重问题,如死锁(JVM不会保证hooks的执行顺序,如果hooks中的代码缺少足够的同步,会造成死锁,及不一致)

  • JVM不保证Shutdown Hooks的执行顺序
  • Shutdown Hooks一旦开始执行,只能通过Runtime.halt()命令来停止hooks的执行,调用System.exit()并不能停止hooks的执行
  • 如果Shutdown Hook中抛出了异常,并且没有被捕获,那么JVM会使用default exception handler来处理异常

tomcat中Shutdown hook的应用

tomcat在启动容器之后,会向JVM注册一个Shutdown hook用于确保tomcat应用即使是在异常退出之后,仍然能够保证资源被正确的释放掉,下面是org.apache.catalina.startup.Catalina类的start()方法的片段

// Register shutdown hook
if (useShutdownHook) {
    if (shutdownHook == null) {
        shutdownHook = new CatalinaShutdownHook();
    }
    Runtime.getRuntime().addShutdownHook(shutdownHook);

    // If JULI is being used, disable JULI's shutdown hook since
    // shutdown hooks run in parallel and log messages may be lost
    // if JULI's hook completes before the CatalinaShutdownHook()
    LogManager logManager = LogManager.getLogManager();
    if (logManager instanceof ClassLoaderLogManager) {
        ((ClassLoaderLogManager) logManager).setUseShutdownHook(
                false);
    }
}

下面是CatalinaShutdownHook的定义:

protected class CatalinaShutdownHook extends Thread {

    @Override
    public void run() {
        try {
            if (getServer() != null) {
                Catalina.this.stop();
            }
        } catch (Throwable ex) {
            ExceptionUtils.handleThrowable(ex);
            log.error(sm.getString("catalina.shutdownHookFail"), ex);
        } finally {
            // If JULI is used, shut JULI down *after* the server shuts down
            // so log messages aren't lost
            LogManager logManager = LogManager.getLogManager();
            if (logManager instanceof ClassLoaderLogManager) {
                ((ClassLoaderLogManager) logManager).shutdown();
            }
        }
    }
}

可以看到tomcat使用Shutdown Hook来确保,Server和LoggerManager正常关闭,为了避免因Server关闭先于LoggerManager导致日志消息丢失的问题,LoggerManager并没有直接使用Shutdown Hook来关闭。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值