销毁线程的创建
在DruidDataSource创建后,调用init()方法进行连接池初始化的时候.会创建一个销毁线程.
方法分析
createAndStartDestroyThread();
createAndStartDestroyThread
通过设置destroyScheduler
来区分创建方式,一种是通过定时任务机制去执行配置的destroyTask
,另外中是直接创建默认销毁线程任务
// 间隔为 timeBetweenEvictionRunsMillis
protected void createAndStartDestroyThread() {
// 创建destory任务
destroyTask = new DestroyTask();
// 如果设置了destroyScheduler
if (destroyScheduler != null) {
//间隔时间 = timeBetweenEvictionRunsMillis = 默认60000ms = 60s
long period = timeBetweenEvictionRunsMillis;
if (period <= 0) {
// 如果1000ms = 1s
period = 1000;
}
// 创建一个间隔为period,并且延迟period启动的任务
destroySchedulerFuture = destroyScheduler.scheduleAtFixedRate(destroyTask, period, period,
TimeUnit.MILLISECONDS);
// 外层代码等待此处创建完成扣减栅栏数
initedLatch.countDown();
return;
}
String threadName = "Druid-ConnectionPool-Destroy-" + System.identityHashCode(this);
// 启动线程
destroyConnectionThread = new DestroyConnectionThread(threadName);
destroyConnectionThread.start();
}
DestroyConnectionThread
线程里睡眠60s,并且调用了DestoryTask
public class DestroyConnectionThread extends Thread {
public DestroyConnectionThread(String name) {
super(name);
this.setDaemon(true);
}
public void run() {
initedLatch.countDown();
System.out.println("DestroyConnectionThread initedLatch countDown " + initedLatch.getCount());
for (; ; ) {
// 从前面开始删除
try {
if (closed || closing) {
break;
}
if (timeBetweenEvictionRunsMillis > 0) {
Thread.sleep(timeBetweenEvictionRunsMillis);
} else {
Thread.sleep(1000); //
}
if (Thread.interrupted()) {
break;
}
destroyTask.run();
} catch (InterruptedException e) {
break;
}
}
}
}
DestroyTask
真正回收连接的任务.
public class DestroyTask implements Runnable {
public DestroyTask() {
}
@Override
public void run() {
shrink(true, keepAlive);
// 是否开启了强制回收连接
if (isRemoveAbandoned()) {
removeAbandoned();
}
}
}
shrink
判断连接池中对象是否存活,如果不满足则剔除.
/**
*
* @param checkTime
* @param keepAlive
* checkTime = true
*/
public void shrink(boolean checkTime, boolean keepAlive) {
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
return;
}
// 是否要填充
boolean needFill = false;
// 踢出数量
int evictCount = 0;
// 还活着几个,每次机选poolingCount
int keepAliveCount = 0;
// 错误计数器
int fatalErrorIncrement = fatalErrorCount - fatalErrorCountLastShrink;
fatalErrorCountLastShrink = fatalErrorCount;
try {
// 初始化完成才做,没创建好的连接池有什么好销毁线程的呢
if (!inited) {
return;
}
// 检查的数量,池子里至少要保持有minIdle个连接,不能全干掉
final int checkCount = poolingCount - minIdle;
final long currentTimeMillis = System.currentTimeMillis();
// 对当前的连接池,而不是活跃的连接池进行循环
for (int i = 0; i < poolingCount; ++i) {
DruidConnectionHolder connection = connections[i];
// 如果有错误,并且发生错误的最后时间已经超过了连接时间,说明这个连接大概率死了,需要剔除
if ((onFatalError || fatalErrorIncrement > 0) && (lastFatalErrorTimeMillis > connection.connectTimeMillis)) {
// 加入到保活列表
keepAliveConnections[keepAliveCount++] = connection;
continue;
}
if (checkTime) {
// 对物理链接超时的连接 移到剔除列表
if (phyTimeoutMillis > 0) {
long phyConnectTimeMillis = currentTimeMillis - connection.connectTimeMillis;
if (phyConnectTimeMillis > phyTimeoutMillis) {
evictConnections[evictCount++] = connection;
continue;
}
}
// 当前时间减去上一次活跃时间 = 空闲时间
long idleMillis = currentTimeMillis - connection.lastActiveTimeMillis;
// minEvictableIdleTimeMillis = 默认1800s 30分钟
if (idleMillis < minEvictableIdleTimeMillis
// keepAliveBetweenTimeMillis 默认2分钟
&& idleMillis < keepAliveBetweenTimeMillis
) {
break;
}
// 对空闲的连接进行回收 minEvictableIdleTimeMillis 默认30分钟
if (idleMillis >= minEvictableIdleTimeMillis) {
if (checkTime && i < checkCount) {
// 加入到剔除
evictConnections[evictCount++] = connection;
continue;
// 对空闲时间超过最大容忍的时间
} else if (idleMillis > maxEvictableIdleTimeMillis) {
// 加入到剔除
evictConnections[evictCount++] = connection;
continue;
}
}
// 开启keepAlive 并且 空闲时间 大于等于 2分钟
if (keepAlive && idleMillis >= keepAliveBetweenTimeMillis) {
// keepAliveConnections也是要被剔除的连接 指的是开启keepAlive时要被剔除的数据结构
keepAliveConnections[keepAliveCount++] = connection;
}
} else {
// 如果checkTime =false 一般为true,那么当前连接小于检查的总数,直接剔除
if (i < checkCount) {
evictConnections[evictCount++] = connection;
} else {
break;
}
}
}
// 最后要删除的数量
int removeCount = evictCount + keepAliveCount;
if (removeCount > 0) {
System.arraycopy(connections, removeCount, connections, 0, poolingCount - removeCount);
Arrays.fill(connections, poolingCount - removeCount, poolingCount, null);
poolingCount -= removeCount;
}
keepAliveCheckCount += keepAliveCount;
// 如果总连接数小于了最小数量 那么需要填充连接池
if (keepAlive && poolingCount + activeCount < minIdle) {
needFill = true;
}
} finally {
lock.unlock();
}
// 开始移除
if (evictCount > 0) {
for (int i = 0; i < evictCount; ++i) {
DruidConnectionHolder item = evictConnections[i];
Connection connection = item.getConnection();
JdbcUtils.close(connection);
destroyCountUpdater.incrementAndGet(this);
}
// 赋值为null 就是删除了 等gc回收
Arrays.fill(evictConnections, null);
}
// 对于应该要被剔除,但是配置了保活策略的对象,需要额外进行验证后才能剔除
if (keepAliveCount > 0) {
// keep order
for (int i = keepAliveCount - 1; i >= 0; --i) {
DruidConnectionHolder holer = keepAliveConnections[i];
Connection connection = holer.getConnection();
holer.incrementKeepAliveCheckCount();
boolean validate = false;
try {
this.validateConnection(connection);
validate = true;
} catch (Throwable error) {
if (LOG.isDebugEnabled()) {
LOG.debug("keepAliveErr", error);
}
// skip
}
boolean discard = !validate;
if (validate) {
// 获取心跳时间
holer.lastKeepTimeMillis = System.currentTimeMillis();
//
boolean putOk = put(holer, 0L, true);
if (!putOk) {
discard = true;
}
}
if (discard) {
try {
connection.close();
} catch (Exception e) {
// skip
}
lock.lock();
try {
discardCount++;
if (activeCount + poolingCount <= minIdle) {
emptySignal();
}
} finally {
lock.unlock();
}
}
}
this.getDataSourceStat().addKeepAliveCheckCount(keepAliveCount);
Arrays.fill(keepAliveConnections, null);
}
// 如果剔除后的连接池里的链接数小于了minIdle 补上
if (needFill) {
lock.lock();
try {
int fillCount = minIdle - (activeCount + poolingCount + createTaskCount);
for (int i = 0; i < fillCount; ++i) {
emptySignal();
}
} finally {
lock.unlock();
}
} else if (onFatalError || fatalErrorIncrement > 0) {
lock.lock();
try {
emptySignal();
} finally {
lock.unlock();
}
}
}
强制回收策略
/**
* 强制回收
* @return
*/
public int removeAbandoned() {
int removeCount = 0;
long currrentNanos = System.nanoTime();
List<DruidPooledConnection> abandonedList = new ArrayList<DruidPooledConnection>();
// 锁住当前活跃的连接
activeConnectionLock.lock();
try {
Iterator<DruidPooledConnection> iter = activeConnections.keySet().iterator();
// 依次获取
for (; iter.hasNext(); ) {
DruidPooledConnection pooledConnection = iter.next();
if (pooledConnection.isRunning()) {
continue;
}
// 当前时间 减去 连接时间
long timeMillis = (currrentNanos - pooledConnection.getConnectedTimeNano()) / (1000 * 1000);
// 如果大于了5分钟
if (timeMillis >= removeAbandonedTimeoutMillis) {
// 从activeConnections移除
iter.remove();
pooledConnection.setTraceEnable(false);
// 加入回收列表
abandonedList.add(pooledConnection);
}
}
} finally {
activeConnectionLock.unlock();
}
// 强制回收的列表里有数据
if (abandonedList.size() > 0) {
for (DruidPooledConnection pooledConnection : abandonedList) {
final ReentrantLock lock = pooledConnection.lock;
lock.lock();
try {
if (pooledConnection.isDisable()) {
continue;
}
} finally {
lock.unlock();
}
JdbcUtils.close(pooledConnection);
pooledConnection.abandond();
removeAbandonedCount++;
removeCount++;
// 如果配置了打印强制回收的日志,一般配置了强制回收肯定也要配置true
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;
}