shutdownHook

观察org.apache.catalina.startup.Catalina中的start()方法,我们发现Serever启动后,还要执行如下代码:

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

加粗部分代码的作用是在jvm中增加一个关闭钩子,当jvm关闭的时候,会先执行系统中通过addShutdownHook()添加的钩子,当系统执行完这些钩子后,jvm才会关闭。这些钩子会在jvm关闭时进行对象销毁、内存清理等操作。

shutdownHook的意义如下:
1.应用程序正常退出,在退出时执行特定的业务逻辑,或者关闭资源等操作。

public class JVMHook {
    public static void start() {
        System.out.println("The JVM is started");
        Runtime.getRuntime().addShutdownHook(new Thread() {
            public void run() {
                try {
                    System.out.println("The JVM Hook is execute");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public static void main(String[] args) {
        start();
        System.out.println("The Application is doing something");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

如上模拟了正常退出的场景,程序执行结果是”
The JVM is started
The Application is doing something
The JVM Hook is execute

我们再来看一下Tomcat服务器shutdown时执行的stop()方法

    /**
     * Stop an existing server instance.
     */
    public void stop() {

        try {
            // Remove the ShutdownHook first so that server.stop()
            // doesn't get invoked twice
            if (useShutdownHook) {
                Runtime.getRuntime().removeShutdownHook(shutdownHook);

                // If JULI is being used, re-enable JULI's shutdown to ensure
                // log messages are not lost
                LogManager logManager = LogManager.getLogManager();
                if (logManager instanceof ClassLoaderLogManager) {
                    ((ClassLoaderLogManager) logManager).setUseShutdownHook(
                            true);
                }
            }
        } catch (Throwable t) {
            ExceptionUtils.handleThrowable(t);
            // This will fail on JDK 1.2. Ignoring, as Tomcat can run
            // fine without the shutdown hook.
        }

此处就会移除关闭钩子!

2.虚拟机非正常退出,比如用户按下ctrl+c、OutofMemory宕机、操作系统关闭等。在退出时执行必要的挽救措施。

public class JVMHook {
    public static void start() {
        System.out.println("The JVM is started");
        Runtime.getRuntime().addShutdownHook(new Thread() {
            public void run() {
                try {
                    System.out.println("The JVM Hook is execute");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public static void main(String[] args) {
        start();
        System.out.println("The Application is doing something");
        byte[] b = new byte[5000 * 1024 * 1024];
        System.out.println("The Application continues to do something");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

同时添加启动参数:-Xms10m -Xmx10m -XX:MaxPermSize=10m
添加启动参数

如上模拟了内存溢出的场景,执行结果如下:
执行结果

当然,使用钩子要注意竞争条件或死锁问题,建议关闭操作在单个线程中串行执行。同一个JVM最好只使用一个关闭钩子,而不是每个服务都使用一个不同的关闭钩子,使用多个关闭钩子可能会出现当前这个钩子所要依赖的服务可能已经被另外一个关闭钩子关闭了。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值