调用/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
相关产品推荐
相关产品推荐

