在init方法中会启动销毁线程
com.alibaba.druid.pool.DruidDataSource#createAndStartDestroyThread
protected void createAndStartDestroyThread() {
destroyTask = new DestroyTask();
if (destroyScheduler != null) {
long period = timeBetweenEvictionRunsMillis;
if (period <= 0) {
period = 1000;
}
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();
}
com.alibaba.druid.pool.DruidDataSource.DestroyConnectionThread
public class DestroyConnectionThread extends Thread {
public DestroyConnectionThread(String name) {
super(name);
this.setDaemon(true);
}
public void run() {
initedLatch.countDown();
for (; ; ) {
// 从前面开始删除
try {
if (closed || closing) {
break;
}
if (timeBetweenEvictionRunsMillis > 0) {
Thread.sleep(timeBetweenEvictionRunsMillis);//60s
} else {
Thread.sleep(1000); //
}
if (Thread.interrupted()) {
break;
}
destroyTask.run();
} catch (InterruptedException e) {
break;
}
}
}
}
com.alibaba.druid.pool.DruidDataSource.DestroyTask
public class DestroyTask implements Runnable {
public DestroyTask() {
}
@Override
public void run() {
shrink(true, keepAlive);
if (isRemoveAbandoned()) {
removeAbandoned();
}
}
}
com.alibaba.druid.pool.DruidDataSource#shrink(boolean, boolean)
public void shrink(boolean checkTime, boolean keepAlive) {
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
return;
}
boolean needFill = false;
int evictCount = 0;
int keepAliveCount = 0;
int fatalErrorIncrement = fatalErrorCount - fatalErrorCountLastShrink;
fatalErrorCountLastShrink = fatalErrorCount;
try {
if (!inited) {
return;
}
// 池子里可用的资源数-最小空闲数 = 需要销毁的资源数
final int checkCount = poolingCount - minIdle;
final long currentTimeMillis = System.currentTimeMillis();
for (int i = 0; i < poolingCount; ++i) {
DruidConnectionHolder connection = connections[i];
// 这几个参数不知道,满足条件后会把连接放进keepAliveConnections,然后下一个
if ((onFatalError || fatalErrorIncrement > 0) && (lastFatalErrorTimeMillis > connection.connectTimeMillis)) {
keepAliveConnections[keepAliveCount++] = connection;
continue;
}
// 检查时间
if (checkTime) {
// 如果设置了物理连接过期时间
if (phyTimeoutMillis > 0) {
long phyConnectTimeMillis = currentTimeMillis - connection.connectTimeMillis;
if (phyConnectTimeMillis > phyTimeoutMillis) {
// 连接使用时间大于阈值,将 holder 保存到 evictConnections 中
evictConnections[evictCount++] = connection;
continue;
}
}
// 当前时间-上次活跃时间 = 空闲时间
long idleMillis = currentTimeMillis - connection.lastActiveTimeMillis;
// 空闲时间小于最小可驱逐空闲时间并且小于保活时间,下面两个不用执行了,
// 我理解应该是 continue ????? 但是为什么停止循环????
// holder在connection中按照时间的排序的么?这样可以解释
if (idleMillis < minEvictableIdleTimeMillis
&& idleMillis < keepAliveBetweenTimeMillis
) {
break;
}
// 空闲时间大于最小可驱逐时间阈值
if (idleMillis >= minEvictableIdleTimeMillis) {
// 清除额度
if (checkTime && i < checkCount) {
evictConnections[evictCount++] = connection;
continue;
// 这种情况必须清除
} else if (idleMillis > maxEvictableIdleTimeMillis) {
evictConnections[evictCount++] = connection;
continue;
}
}
//空闲时间大于保活时间的,同样也要清除,因为过了保活的时间
if (keepAlive && idleMillis >= keepAliveBetweenTimeMillis) {
keepAliveConnections[keepAliveCount++] = connection;
}
} else {
// 不需要检查参数,数出需要销毁的,直接放进 evictConnections
if (i < checkCount) {
evictConnections[evictCount++] = connection;
} else {
break;
}
}
}
// 所有要清理的数量
int removeCount = evictCount + keepAliveCount;
if (removeCount > 0) {
// 将后面的存活的holder直接前移覆盖移除的holder
System.arraycopy(connections, removeCount, connections, 0, poolingCount - removeCount);
// 将后面的置为null
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(); // ConnectionProxyImpl
JdbcUtils.close(connection); // 关闭物理连接
destroyCountUpdater.incrementAndGet(this);
}
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; // discard 放弃,无效的放弃
if (validate) {
holer.lastKeepTimeMillis = System.currentTimeMillis();
// 向connections存放holder,如果放置成功,则返回true
// 如果connections中存在当前holder 或者池中资源大于最大活动数,返回false
boolean putOk = put(holer, 0L, true);
if (!putOk) {
// 为什么connections中存在keepLive中的holder,要把这个关闭??不理解
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);
}
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();
}
}
}
本文深入探讨Java编程中线程销毁的重要方法——shrink。内容聚焦于如何在初始化过程中启动销毁线程,并分析其在排序算法和多线程开发中的应用。
2961

被折叠的 条评论
为什么被折叠?



