HikariCP 的 ConcurrentBag 不提供“借用连接列表”,因其内部无统一 borrowed list,仅通过 ThreadLocal、sharedList 和原子状态管理租借关系,且所有关键类为包私有、版本间结构不兼容,反射访问既不可靠也不安全。

Java 中无法通过反射安全、稳定地获取 HikariCP 内部 ConcurrentBag 的“借用连接列表”,因为该设计是刻意隐藏且不对外暴露的实现细节。
为什么不能直接获取借用连接列表
HikariCP 的 ConcurrentBag 是一个高度优化的无锁并发容器,其内部维护了三种状态的连接:未使用(idle)、正在被借用(borrowed/leased)、待回收(reserved)。但“借用中”的连接并不以公开列表形式存在:
- 它用
ThreadLocal+CopyOnWriteArrayList+ 原子引用计数等方式管理租借关系,没有统一的“borrowed list”字段; - 核心字段如
sharedList(存放 idle 和 reserved 连接)和threadList(每个线程本地缓存)都不直接反映全局借用状态; - HikariCP 明确禁止外部访问
ConcurrentBag,所有内部类(如ConcurrentBag、BagEntry)都是包私有(package-private),且随版本频繁变更。
替代方案:通过官方 API 获取连接使用情况
若目标是监控或诊断连接是否被长期占用,应优先使用 HikariCP 提供的公开指标:
-
HikariPoolMXBean:可通过 JMX 获取activeConnections(当前活跃连接数),即已借出未归还的数量; -
HikariDataSource.getHikariPoolMXBean().getActiveConnections()直接返回整型值; - 开启
leakDetectionThreshold(例如设为 60000 毫秒),当连接借用超时会自动打印堆栈,定位泄漏点; - 配合日志级别设为
DEBUG,HikariCP 会在 borrow/return 时输出连接生命周期事件(需启用com.zaxxer.hikari日志前缀)。
反射强行访问的风险与局限
即使使用反射尝试读取 ConcurrentBag 内部状态,也会遇到以下问题:
立即学习“Java免费学习笔记(深入)”;
- 字段名、结构在不同 HikariCP 版本中差异极大(如 4.x 和 5.x 完全重构了
ConcurrentBag); - 关键字段如
state(BagEntry状态)是volatile int,需解读状态码(如 1=reserved, 2=used),但无文档保证; - 无法准确区分“正在使用”和“已标记为泄露但尚未回收”的连接;
- 反射破坏封装,导致应用在升级依赖后突然崩溃或行为异常,不适用于生产环境。
真需要调试时的可行做法
如果仅用于开发期临时排查(非生产),可考虑:
- 在测试代码中继承
HikariConfig并设置registerJmx(true),再通过 JConsole 或 VisualVM 查看 MBean 属性; - 用字节码增强工具(如 ByteBuddy)在
ConcurrentBag.borrow()和ConcurrentBag.requite()方法前后插入日志,记录线程 ID 与连接哈希; - 利用 JVM 自带的
jstack+grep查找持有HikariProxyConnection的线程栈,手动分析阻塞点。
不复杂但容易忽略:连接池健康的关键不在“看到借用列表”,而在控制借用逻辑本身——确保 try-with-resources 正确关闭、避免连接跨线程传递、防止事务未提交导致连接卡住。


















