简单介绍shutdownHook-Java服务优雅关闭

背景

在高并发场景下,服务发布或异常退出时,未完成的数据处理(如订单支付、资源释放)可能导致数据不一致。例如:服务在无事务保护下中断,会使部分数据滞留于中间状态(如 “处理中”“锁定”),需人工介入修复。为提升系统稳定性,引入优雅关闭机制,确保服务终止前完成必要的资源清理和数据持久化

用法

在Spring中提供了一个钩子,当jvm收到关闭通知之后(Kill -15),就会调用钩子中的方法,钩子中的方法执行完成后才会退出服务。
服务启动类中添加,Runtime.getRuntime().addShutdownHook(Thread) 需要传入一个线程对象,后续动作将会在该异步线程内完成
JVM 层面的 ShutdownHook,可直接注册 JVM 关闭钩子:

public class Application {
    public static void main(String[] args) {
        // 注册关闭钩子
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            log.info("Shutdown hook triggered, performing cleanup...");
            try {
                // 资源释放逻辑(如关闭连接池)
                databaseClient.close();
                cacheClient.disconnect();
                log.info("Cleanup completed, exiting");
            } catch (Exception e) {
                log.error("Error during shutdown", e);
            }
        }, "shutdown-hook-thread"));

        // 应用启动逻辑
        startServer();
    }
}

Spring 框架集成方案
Spring 提供DisposableBean、@PreDestroy和ApplicationListener<ContextClosedEvent>等多种优雅关闭方案

@Component
public class ThreadPoolCollect implements DisposableBean {
    /**
     * 优雅关闭线程池
     */
    @Override
    public void destroy() throws Exception {
        shutdownThreadPool(commonThreadPool, "commonThreadPool");
        shutdownThreadPool(shardMetaThreadPool, "shardMetaThreadPool");
    }
}

除了主动关闭应用(使用 kill -15 指令),以下场景也将会触发 ShutdownHook :
代码执行结束,JVM 正常退出
应用代码中调用 System#exit 方法
应用中发生 OOM 错误,导致 JVM 关闭
终端中使用 Ctrl+C(非后台运行)

原理分析

后面有空再补充。

注意事项

1、ShutdownHook 需要尽快执行结束,比如使用while(true) 会导致服务一直没办法倍关闭;
2、不能使用Kill -9关闭服务,会导致不会调用shutdownHook;
3、shutdownHook的方法应该是线程安全的,因为可能发送信号导致方法被不同的线程多次调用;
4、shutdownHook调用过程中产生的所有异常都会被忽略掉;

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容