Tomcat停止时出现pool-(x)-thread-(y)阻塞线程导致关闭耗时久如何解决
根因定位
你遇到的是mariadb-java-client 2.3.x版本的已知Bug:该版本驱动内部会默认创建一个无显式销毁逻辑的异步线程池,用于处理连接超时检测、异步批量查询等逻辑,线程命名就是默认的pool-(x)-thread-(y)格式,应用停止时驱动不会主动关闭该线程池,进而导致Tomcat容器回收web应用资源时阻塞,触发内存泄漏告警。
验证方法
在应用启动参数中添加如下配置,禁用驱动内部的异步超时线程池:
-Dmariadb.enableAsyncTimeouts=false
重启应用后再执行停止操作,如果阻塞线程消失即可确认是该驱动问题导致。
解决方案
- 最优方案:升级驱动版本
直接升级mariadb-java-client到2.7.10+或者3.0.3+版本,上述版本已经修复了线程池未主动关闭的问题,和Spring 4.x/5.x版本兼容性良好,无需修改业务代码。 - 临时兼容方案(无法升级版本时使用)
在Spring Bean的销毁逻辑中主动关闭数据库连接池,示例代码如下:
@PreDestroy public void closeDataSource() throws SQLException { if (dataSource != null) { dataSource.close(); } }
也可以直接在数据库连接配置中添加禁用异步超时的参数,避免内部线程池创建:
spring.datasource.url=jdbc:mariadb://xxx:3306/xxx?enableAsyncTimeouts=false
- 长期排查优化
后续所有自定义线程池、第三方依赖的线程池都尽量配置自定义线程工厂,给线程加上业务标识前缀,避免默认命名导致的问题排查困难。
额外排查方向
如果处理完驱动问题后仍存在同格式阻塞线程,可以排查其他未配置销毁逻辑的中间件客户端(Redis、MQ客户端等),这类组件如果使用默认线程池配置,也会生成pool-(x)-thread-(y)格式的线程,可通过Arthas的thread命令过滤对应线程,查看其上下文类加载器关联的依赖,快速定位来源。
内容的提问来源于stack exchange,提问作者Tobia
相关产品推荐
相关产品推荐

