// 回收长期未归还的连接(再次说明:该方法仅在 removeAbandoned 设置为 true 的情况下触发)
public int removeAbandoned() {
int removeCount = 0;
long currrentNanos = System.nanoTime();
// 这个列表用于存放满足条件的真正需要强制回收的连接
List<DruidPooledConnection> abandonedList = new ArrayList<DruidPooledConnection>();
activeConnectionLock.lock();
try {
//在 removeAbandoned 设置为 true 的情况下,所有被借出去的连接,都会被保存进 activeConnections(参考主流程1),所以要进行“长期未归还”的检查,就是从 activeConnections 开始的
Iterator<DruidPooledConnection> iter = activeConnections.keySet().iterator();
for (; iter.hasNext();) {
DruidPooledConnection pooledConnection = iter.next();
if (pooledConnection.isRunning()) {
// 如果当前连接正在使用中(指的是正在 execute),则不处理
continue;
}
// 利用当前时间和连接被借出去时的时间,计算出连接被借出去的时间有多久
long timeMillis = (currrentNanos - pooledConnection.getConnectedTimeNano()) / (1000 * 1000);
// 如果连接被借出去的时间超过 removeAbandonedTimeoutMillis 这个阈值,将会命中“主动归还”的逻辑检查
if (timeMillis >= removeAbandonedTimeoutMillis) {
// 先从 activeConnections 移除
iter.remove();
// 标记为 false,防止回收时重复 removeactiveConnections,可以参考主流程5
pooledConnection.setTraceEnable(false);
// 放入“强制回收”队列
abandonedList.add(pooledConnection);
}
}
} finally {
activeConnectionLock.unlock();
}
// 如果“强制回收”队列大于 0,说明有需要回收的连接
if (abandonedList.size() > 0) {
// 循环这些连接
for (DruidPooledConnection pooledConnection : abandonedList) {
final ReentrantLock lock = pooledConnection.lock;
// 拿到连接的锁
lock.lock();
try {
// 已经被回收的,则不管
if (pooledConnection.isDisable()) {
continue;
}
} finally {
lock.unlock();
}
// 触发回收连接对象(pooledConnection)里的 holcder(注意这里其实是把 pooledConnection 对象里的 holder 给回收至连接池了,pooledConnection 对象本身会被销毁)
// 这里触发的 close,是 DruidPooledConnection 的 close,也就是会触发 recycle 方法的 close
JdbcUtils.close(pooledConnection);
// 标记
pooledConnection.abandond();
removeAbandonedCount++;
removeCount++;
// 日志打印,忽略
if (isLogAbandoned()) {
StringBuilder buf = new StringBuilder();
buf.append("abandon connection, owner thread: ");
buf.append(pooledConnection.getOwnerThread().getName());
buf.append(", connected at : ");
buf.append(pooledConnection.getConnectedTimeMillis());
buf.append(", open stackTrace\n");
StackTraceElement[] trace = pooledConnection.getConnectStackTrace();
for (int i = 0; i < trace.length; i++) {
buf.append("\tat ");
buf.append(trace[i].toString());
buf.append("\n");
}
buf.append("ownerThread current state is " + pooledConnection.getOwnerThread().getState()
+ ", current stackTrace\n");
trace = pooledConnection.getOwnerThread().getStackTrace();
for (int i = 0; i < trace.length; i++) {
buf.append("\tat ");
buf.append(trace[i].toString());
buf.append("\n");
}
LOG.error(buf.toString());
}
}
}
// 返回本次被强制回收的连接个数
return removeCount;
}