②检查本地保存的连接
//②
//如果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 &#