九、HikariCP 源码分析之 ConcurrentBag 二

本文详细分析了HikariCP的ConcurrentBag在检查本地线程保存的连接及连接状态,讨论了如何确保线程安全并高效地获取连接。在遍历连接时采取倒序策略,优先检查最近使用的连接。当无法从本地获取连接时,进行一系列准备工作,包括设置超时时间,记录开始时间等。在连接池中尝试获取连接,如果成功则判断是否需要补偿其他等待线程创建新连接。如果没有获取到连接,则会根据超时时间和连接池变化情况决定是否继续尝试,直到达到超时时间,最终返回null。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

②检查本地保存的连接

//②
//如果ThreadLocal中有连接的话, 就遍历, 尝试获取
//从后往前反向遍历是有好处的, 因为最后一次使用的连接, 空闲的可能性比较大, 之前的连接可能会被其他线程偷窃走了
for (int i = list.size() - 1; i >= 0; i--) {
  final Object entry = list.remove(i);
  @SuppressWarnings("unchecked") final T bagEntry = weakThreadLocals ? ((WeakReference<T>) entry).get() : (T) entry;
  if (bagEntry != null && bagEntry.compareAndSet(STATE_NOT_IN_USE, STATE_IN_USE)) {
     return bagEntry;
  }
}

OK,我们继续。这里遍历的 list 变量,是threadList,是当前线程使用过的连接,保存在本地线程的引用。

可以看到这个遍历的顺序,是倒序遍历的。list 里的连接,肯定是最后一个是最后放进去的,也就是最近使用过的,这个连接还可以继续使用的可能极大,时间越早的连接,就越可能被其他线程借用走了,所以这就是为什么要倒序遍历,我们要先检查能使用的可能性最大的连接。说到这里,我们在平时的业务代码中,要用 if 检查一些条件,这时候我们要有意识的先检查可能性最大的条件,这有利于减少判断的次数,提高程序的性能。

在从 list 中获取连接的时候,使用的是remove方法,也就是说,无论如何,这个连接的引用我们不在本地保存了,如果它可以用,那么用完之后它又会加入到本地的threadList,如果不能使用了,那么我们就删除了这个无用的连接引用。

下面第 三句代码其实就是类型的强转,忽略之。有意思的是接下来第四句的判断,直接在 if 中就执行修改连接状态的操作。每个连接都有一个状态,它的类型是AtomicInteger,是个数字,并且是原子操作,线程安全。compareAndSet方法执行的时候,将STATE_NOT_IN_USE状态跟连接的当前状态对比,一样的时候才将它修改成STATE_IN_USE,既保证了线程安全,又保证了只有在连接是空闲状态才能使用线程,不会错误使用了其他状态的连接。此时,如果状态修改成功了,那么直接将该连接返回给用户使用。

说到这里,应该说一下连接有哪些状态。

连接的状态

STATE_NOT_IN_USE &#

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值