所属文章:池化技术(一)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;
}

Druid-代码段-4-2的更多相关文章

  1. WPF自定义RoutedEvent事件代码段

    今天在写东西的时候,发现常用的代码段里没有RoutedEvent的,因此,写了一个代码段,方便以后使用,顺便记录一下,如何做代码段. 1.在项目中新建一个XML文件,将扩展名修改为snippet. 2 ...

  2. JavaScript代码段整理笔记系列(二)

    上篇介绍了15个常用代码段,本篇将把剩余的15个补齐,希望对大家有所帮助!!! 16.检测Shift.Alt.Ctrl键: event.shiftKey; //检测Shift event.altKey ...

  3. 我们为什么要看《超实用的Node.JS代码段》

    不知道自己Node.JS水平如何?看这张图 如果一半以上的你都不会,必须看这本书,一线工程师用代码和功能页面来告诉你每一个技巧点. 都会一点,但不知道如何检验自己,看看本书提供的面试题: 1.     ...

  4. 《超实用的JavaScript代码段》—— 读后总结

    这本书全是代码,从头到尾跟着坐下来确实收获很多.比那些古板的教科书式的理解更多,不过书中并不是每个例子都做了,有的作者封装的太多,觉得看了收获不多,就没细看——比如模块渐变.有空好好学学这段的代码. ...

  5. Visual Studio常用小技巧一:代码段+快捷键+插件=效率

    用了visual studio 5年多,也该给自己做下备忘录了.每次进新的组换新的电脑,安装自己熟悉的环境又得重新配置,不做些备忘老会忘记一些东西.工具用的好,效率自然翻倍. 1,代码段 在Visua ...

  6. 使用eclipse开发Morphline的Java代码段

    背景:morphline是一个轻量级的etl工具.除了提供标准化的方法之外,还可以定制化的开发java片段.定制化的java片段会在加载时被作为一个独立的类编译,对源数据作处理. morphline关 ...

  7. 前端福利!10个短小却超实用的JavaScript 代码段

    JavaScript正变得越来越流行,它已经成为前端开发的第一选择,并且利用基于JavaScript语言的NodeJS,我们也可以开发出高 性能的后端服务,甚至我还看到在硬件编程领域也出现了JavaS ...

  8. Visual C# 代码段

    代码段是现成的代码段,您可以快速将其插入到您的代码中. 例如,for 代码段创建一个空的 for 循环. 有些代码段为外侧代码段,这些代码段允许您先选择代码行,然后选择要并入选定代码行的代码段. 例如 ...

  9. 十五个常用的jquery代码段【转】

    好的文章顶一个 回到顶部按钮 通过使用 jQuery 中的 animate 和 scrollTop 方法,你无需插件便可创建一个简单地回到顶部动画: 1 // Back to top 2 $('a.t ...

  10. 十五个常用的jquery代码段

    十五个常用的jquery代码段 回到顶部按钮 通过使用 jQuery 中的 animate 和 scrollTop 方法,你无需插件便可创建一个简单地回到顶部动画: 1 // Back to top ...

随机推荐

  1. vc6.0 绿色版 下载地址

    最新版的vs2019已经完全不支持生成运行在xp下的应用程序 每次在xp下测试,都需要配置好vc6.0,但乱七八糟的太多了,给出地址,绿色版可用 http://www.downcc.com/soft/ ...

  2. Eigen对齐(加速)方案

    Eigen库为了使用指令集(如SSE等)加速方案,通常采用字节对齐的方案.如果使用C++的标准库,如Vector,Map等,需要使用如下方案 std::map<int, Eigen::Vecto ...

  3. SAP QM 检验批里某检验特性的取样数量跟检验计划设置不符?

    SAP QM 检验批里某检验特性的取样数量跟检验计划设置不符? 如下检验批号 890000045939, 结果录入界面,第二个特性里,取样数量是50个.实际上,该检验批对应的检验计划里, 采样过程L- ...

  4. Go语言nil:空值/零值

    在 Go 语言中,布尔类型的零值(初始值)为 false,数值类型的零值为 0,字符串类型的零值为空字符串"",而指针.切片.映射.通道.函数和接口的零值则是 nil. nil 是 ...

  5. centos7中安装python3.6.4

    1.在安装Python之前,需要先安装一些后面遇到的依赖问题(如果有依赖问题,按照提示安装): yum -y install zlib-devel bzip2-devel openssl-devel ...

  6. springboot+quartz+数据库存储

    Spring整合Quartz a.quartz调度框架是有内置表的 进入quartz的官网http://www.quartz-scheduler.org/,点击Downloads, 下载后在目录\do ...

  7. Registering current configuration as safe fallback point

    14:28:23,255 |-INFO in ch.qos.logback.core.joran.spi.ConfigurationWatchList@f5f2bb7 - URL [jar:file: ...

  8. 西北师大-2108Java】第十三次作业成绩汇总

    [西北师大-2108Java]第十三次作业成绩汇总 作业题目 面向对象程序设计(JAVA) 第15周学习指导及要求 实验目的与要求 (1)掌握菜单组件用途及常用API: (2)掌握对话框组件用途及常用 ...

  9. 通过 Filebeat 收集 ubuntu 系统日志

    需求:收集 ubuntu 系统日志,发送给 logstash,再由 logstash 把数据传递给 elasticsearch,最后通过 kibana 展示日志数据. Filebeat System ...

  10. 【问题记录】 Linux分区磁盘占满,导致ssh登陆闪退

    问题描述 今天要去后台看日志查个问题,通过ssh登陆到服务器后准备用平时非常熟悉的less命令打开日志查看,突然xshell客户端就闪退了.一时感觉很蒙,怎么回事??由于之前有同事遇到类似的问题,提醒 ...