Druid空闲连接回收源码解析
一、概念
(一) DestroyConnectionThread
DestroyConnectionThread负责回收空闲连接,但其中负责回收的代码在DestroyTask内。DestroyConnectionThread执行的时间间隔默认为60s,可以通过time-between-eviction-runs-millis属性修改,如果为0或者负数,时间间隔则为1s。
(二) DestroyTask
DestroyTask才是真正负责空闲线程的回收,符合以下两种条件的空闲连接会被DestroyTask清除:
1. 空闲连接数大于min-idle,且空闲时间大于min-evictable-idle-time-millis
2. 空闲时间大于max-evictable-idle-time-millis的连接
二、源码
//初始化方法
public void init() throws SQLException {
[省略部分代码]
//创建专门用于创建数据库连接的线程--与createAndStartDestroyThread()构成了很典型的生产者消费者
createAndStartCreatorThread();
//创建专门用于回收空闲连接的线程
createAndStartDestroyThread();
[省略部分代码]
}
protected void createAndStartDestroyThread() {
destroyTask = new DestroyTask();
[省略部分代码]
destroyConnectionThread = new DestroyConnectionThread(threadName);
destroyConnectionThread.start();
}
public class DestroyConnectionThread extends Thread {
public DestroyConnectionThread(String name){
super(name);
this.setDaemon(true);
}
public void run() {
[省略部分代码]
//DestroyConnectionThread中最终回收连接的代码还是由DestroyTask来进行
//此处是直接调用DestroyTask的run(),而不是通过start()异步调用
destroyTask.run();
}
}
public class DestroyTask implements Runnable {
[省略部分代码]
@Override
public void run() {
shrink(true, keepAlive);
[省略部分代码]
}
}
public void shrink(boolean checkTime, boolean keepAlive) {
//空闲连接数与min-idle的差值
final int checkCount = poolingCount - minIdle;
//poolingCount--表示连接池中的空闲连接数目
for (int i = 0; i < poolingCount; ++i) {
//connections[]数组的元素都是空闲连接,初始化时候该数组直接初始化为maxActive大小
//connections[]中的连接获取都是从后往前取,通过pollLast(long)或者takeLast()获取connections[--poolingCount],并将connections[poolingCount]置为null,由于空闲连接的获取使用是从后往前获取,所以释放过多空闲连接时只需要迭代connections[]的前poolingCount个元素。
DruidConnectionHolder connection = connections[i];
[省略部分代码]
//当前空闲连接的空闲时长超过了min-evictable-idle-time-millis(连接最小空闲时间,默认为30分钟,单位为ms)时间
if (idleMillis >= minEvictableIdleTimeMillis) {
//空闲连接数大于min-idle,且空闲时间大于最小空闲时间min-evictable-idle-time-millis
if (checkTime && i < checkCount) {
evictConnections[evictCount++] = connection;
continue;
//空闲时长超过连接最大空闲时间max-evictable-idle-time-millis(连接最大空闲时间,默认为7小时,单位为ms),超过最大空闲时间的空闲连接都需要释放,不管当前空闲连接数是否大于最小空闲连接数min-idle
//最大空闲时间max-evictable-idle-time-millis理论上要比最小空闲时间min-evictable-idle-time-millis大,如果小的话,druid初始化的日志中会出现警告warn
} else if (idleMillis > maxEvictableIdleTimeMillis) {
evictConnections[evictCount++] = connection;
continue;
}
}
[省略部分代码]
}
}