You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用/actuator/shutdown后Spring Boot Java进程无法正常终止

Spring Boot优雅关闭失败:Hikari连接池线程导致进程残留

问题分析

从日志可见,Tomcat停止Web应用时先检测到HikariPool-1 housekeeper和HikariPool-2 housekeeper线程未停止,抛出内存泄漏警告;后续Spring才开始销毁Hikari连接池。这种关闭顺序倒置是核心问题:Tomcat的Web应用停止流程先于Spring对Hikari资源的销毁,导致Tomcat标记线程泄漏,而Hikari的清理可能因线程未正确终止、Spring关闭钩子未等待资源清理完成,最终让Java进程无法正常退出。

另外日志中HikariPool-2初始有10个连接,但仅输出6个连接关闭的记录,需排查是否存在日志截断,确认连接池是否完全关闭。

解决方案

1. 调整资源关闭顺序,让Hikari先于Tomcat停止

  • 给HikariDataSource Bean添加@PreDestroy注解,确保Bean销毁时主动关闭连接池:
    @Bean
    public HikariDataSource dataSource() {
        HikariConfig config = new HikariConfig();
        // 配置数据库连接信息
        return new HikariDataSource(config);
    }
    
    @PreDestroy
    public void closeHikari() {
        dataSource().close();
    }
    
  • 配置spring.lifecycle.timeout-per-shutdown-phase参数,延长关闭阶段超时时间,给Hikari足够清理时间:
    spring.lifecycle.timeout-per-shutdown-phase=30s
    

2. 确保Hikari线程为守护线程

Hikari默认housekeeper线程是守护线程,但如果线程属性被修改,会导致非守护线程残留。手动指定线程工厂创建守护线程:

@Bean
public HikariDataSource dataSource() {
    HikariConfig config = new HikariConfig();
    // 其他配置...
    config.setThreadFactory(runnable -> {
        Thread thread = new Thread(runnable);
        thread.setDaemon(true);
        thread.setName("HikariPool-housekeeper");
        return thread;
    });
    return new HikariDataSource(config);
}

3. 排查未完全关闭的资源

  • 执行jstack <进程ID>命令查看当前活跃线程,确认是否有其他非守护线程残留;
  • 检查完整日志,确认HikariPool-2的10个连接是否全部关闭,若未完成,排查数据库连接是否存在阻塞(比如未提交的事务)。

4. 优化Actuator Shutdown触发逻辑

  • 检查自定义的AppShutdownHook是否存在阻塞逻辑,是否等待所有资源清理完成;
  • 配置spring.shutdown.grace-period增加优雅关闭等待时间:
    spring.shutdown.grace-period=20s
    

内容的提问来源于stack exchange,提问作者The Shoe Shiner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 07:37:12