所属文章:池化技术(一)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. jQuery插件 distpicker实现多次赋值

    项目里需要实现省市区联动选择功能,使用了一个jQuery插件dispicker,记录一下使用过程中遇到的问题和解决办法. 需要要实现的功能就两个:打开modal框时设置地址,点击重置按钮时重置地址 原 ...

  2. js-07-事件

    一.js事件绑定在对象上的三种方法 a:将事件绑定在元素标签的属性上 <h3 onclick="console.log('奥特曼打怪兽')">海绵宝宝历险记</h ...

  3. 苹果_公司开发者账号_注册Apple ID

    本文所有网站入口为developer.apple.com 注册Apple ID 注意事项:目前注册信息尽量用拼音或英文,姓名格式正确,记住安全问题,出生日期在18岁以上(小于18岁会出现Sorry,y ...

  4. macOS Catalina Kernel panic 因为意外而重新启动

    0x00 What's Happend? 我的 MacBook Air 在升级到 Catalina 之后,经常在休眠模式重启,随后在桌面上显示"因为意外而重新启动"的信息,以下是跟 ...

  5. 关于ajax请求不到后台页面提示400 bad request的问题

    解决方法一: 在contrller控制器中对应方法的 @RequestMapping注解中添加 method="RequestMethod.POST"属性

  6. Object对象方法ES5

    Object.create(proto,propertiesObject)方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__. 参数: proto:新创建对象的原型对象. pro ...

  7. Java程序远程无法执行nohup命令

    问题的上下文: 由于生产无法使用 jenkins 发布,所以采用 ch.ethz.ssh2 或叫 ganymed-ssh2 的开源 java 的 ssh api 进行远程发布. 在发起重启时,远程执行 ...

  8. Python的标准库介绍与常用的第三方库

    Python的标准库介绍与常用的第三方库 Python的标准库: datetime:为日期和时间的处理提供了简单和复杂的方法. zlib:以下模块直接支持通用的数据打包和压缩格式:zlib,gzip, ...

  9. ubuntu 18.04多应用窗口切换的快捷键使用指南

    前记 使用ubuntu时间长了,很厌烦用鼠标来点来点去.重复操作的,还是快捷键比较方便.在多窗口切换方面,熟悉了几个快捷键之后,顿时感觉神清气爽.这里就推荐给大家学习一下,提高工作效率啊. 常用快捷键 ...

  10. md2all 简单实用

    . 简单使用 md2all 使用地址:http://md.aclickall.com/ . 常用操作 #代表标题等级 英文下```java(语言)``` 代表代码块