所属文章:池化技术(一)Druid是如何管理数据库连接的?

本代码段对应流程4.1,连接池瘦身:


//连接池瘦身
public void shrink(boolean checkTime, boolean keepAlive) {
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
return;
} int evictCount = 0;
int keepAliveCount = 0;
try {
if (!inited) {
return;
} final int checkCount = poolingCount - minIdle; //根据poolingCount和minIdle计算出evictCheck的范围
final long currentTimeMillis = System.currentTimeMillis();
for (int i = 0; i < poolingCount; ++i) { //开始遍历连接池里闲置的连接
DruidConnectionHolder connection = connections[i]; if (checkTime) { //除非手动调用,不然经过主流程4触发,一般为true
if (phyTimeoutMillis > 0) { //默认不启用,忽略
long phyConnectTimeMillis = currentTimeMillis - connection.connectTimeMillis;
if (phyConnectTimeMillis > phyTimeoutMillis) {
evictConnections[evictCount++] = connection;
continue;
}
} //计算闲置时间
long idleMillis = currentTimeMillis - connection.lastActiveTimeMillis; if (idleMillis < minEvictableIdleTimeMillis
&& idleMillis < keepAliveBetweenTimeMillis
) { //如果闲置时间达不到检测&瘦身的阈值,则不处理
break;
} if (idleMillis >= minEvictableIdleTimeMillis) {
if (checkTime && i < checkCount) { //达到需要丢弃的阈值时,则判断连接下标是否在evictCheck范围,若在,则视为“可以丢弃的对象”放入evictConnections数组
evictConnections[evictCount++] = connection;
continue;
} else if (idleMillis > maxEvictableIdleTimeMillis) { //达到必须要丢弃的阈值时,则不管是不是在evictCheck范围内,都直接放入“可以丢弃的对象”的evictConnections数组
evictConnections[evictCount++] = connection;
continue;
}
} //如果上面的条件均没有命中,如果keepAlive为true,则判断是不是超过了闲置连接检查其活性的频次阈值(即由keepAliveBetweenTimeMillis控制)
if (keepAlive && idleMillis >= keepAliveBetweenTimeMillis) {
keepAliveConnections[keepAliveCount++] = connection; //满足条件则视为“需要检测活性的对象”,放入keepAliveConnections数组
}
} else {
if (i < checkCount) {
evictConnections[evictCount++] = connection;
} else {
break;
}
}
} int removeCount = evictCount + keepAliveCount; //这一批需要移除特殊处理的连接总数
if (removeCount > 0) {
System.arraycopy(connections, removeCount, connections, 0, poolingCount - removeCount); //根据当前移除的元素,把剩余的元素移动至数组首部(参考流程4.1)
Arrays.fill(connections, poolingCount - removeCount, poolingCount, null); //剩余位置清空
poolingCount -= removeCount;
}
keepAliveCheckCount += keepAliveCount;
} finally {
lock.unlock();
} if (evictCount > 0) { //如果需要丢弃的连接数量大于0
for (int i = 0; i < evictCount; ++i) {
DruidConnectionHolder item = evictConnections[i];
Connection connection = item.getConnection();
JdbcUtils.close(connection); //直接关闭连接(这里是直接关闭驱动连接,不再放回池子)
destroyCountUpdater.incrementAndGet(this);
}
Arrays.fill(evictConnections, null); //将evictConnections数组重新置空(方便下次使用)
} 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); //检测通过后,再次放入池子
if (!putOk) { //放不进去池子(说明已经达到连接池最大连接数阈值maxActive),则视为可以“直接抛弃”的连接
discard = true;
}
} if (discard) {
try {
connection.close(); //如果可以抛弃,则直接关闭连接(直接调用驱动的close)
} catch (Exception e) {
// skip
} lock.lock();
try {
discardCount++; //抛弃连接数累加 if (activeCount <= minIdle) {
emptySignal(); //唤起主流程3追加连接对象
}
} finally {
lock.unlock();
}
}
}
this.getDataSourceStat().addKeepAliveCheckCount(keepAliveCount);
Arrays.fill(keepAliveConnections, null); //将keepAliveConnections数组重新置空(方便下次使用)
}
} //上面检测通过,再次通过该方法重新把连接放入池子
private boolean put(DruidConnectionHolder holder) {
lock.lock();
try {
if (poolingCount >= maxActive) {
return false; //若池子内闲置连接数超过maxActive,则无法继续添加新的连接进来,返回false
}
connections[poolingCount] = holder; //否则直接把此连接对象放入连接池队尾
incrementPoolingCount(); //poolingCount++ if (poolingCount > poolingPeak) {
poolingPeak = poolingCount;
poolingPeakTime = System.currentTimeMillis();
} notEmpty.signal(); //唤起那些因获取不到可用连接而陷入阻塞状态的业务线程一次
notEmptySignalCount++; if (createScheduler != null) { //不启用该模式,忽略
createTaskCount--; if (poolingCount + createTaskCount < notEmptyWaitThreadCount //
&& activeCount + poolingCount + createTaskCount < maxActive) {
emptySignal();
}
}
} finally {
lock.unlock();
}
return true;
}

最新文章

  1. [weird problem] the xm file transfered by wcf,some sections in it were always repeated
  2. js生成验证码并验证
  3. mount失败
  4. OC - 7.Foundation框架的简单介绍
  5. Silverlight实用窍门系列:47.Silverlight中元素到元素的绑定,以及ObservableCollection和List的使用区别
  6. js - SyntaxError: JSON.parse: unexpected character at line 1 column 2 of the JSON data jquery-1.9.1.min.js:3:4315
  7. Redmine管理项目3-调整用户显示格式
  8. 2014年蓝桥杯预选赛 C/C++ 本科A组试题--切面条
  9. apt-get 总结
  10. nginx响应高并发参数配置
  11. django 第四天
  12. Python 天气查询到实现语音播放
  13. Excel与Google Sheets中实现线性规划求解
  14. idea springboot 父子工程 子工程maven不自动import
  15. stark组件的增删改(新)
  16. C++ vector和list的主要用法区别
  17. 读取html文件,让其中的内容和notepad打开这个html的样子一样。
  18. springmvc(二) ssm框架整合的各种配置
  19. ThinkPHP 框架2.1,2.2和3.0版本开启lite模式导致URL命令执行漏洞
  20. mui---开发直播APP

热门文章

  1. 一分钟理解Java公平锁与非公平锁
  2. 如何修改PhpStorm快捷键
  3. JDK性能分析与故障处理-命令行
  4. This system is not registered with ULN
  5. (办公)记事本_Linux目录
  6. 在项目中常用的JS方法封装
  7. git版本对比
  8. 通过pywin32库来上传文件
  9. 基于docker-compose搭建本地sentry服务
  10. 安卓投屏助手(ARDC)最新版