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

本代码段对应主流程3,新增连接的守护线程:


//DruidDataSource的内部类,对应主流程3,用来补充连接
public class CreateConnectionThread extends Thread { public CreateConnectionThread(String name){
super(name); //重置线程名称
this.setDaemon(true); //标记为守护线程
} //run方法
public void run() {
initedLatch.countDown(); //通知init(主流程2)自己已经启动成功 long lastDiscardCount = 0;
int errorCount = 0;
for (;;) { //死循环
// addLast
try {
lock.lockInterruptibly(); //锁获取
} catch (InterruptedException e2) {
break;
} long discardCount = DruidDataSource.this.discardCount;
//当前丢弃连接数与最后一次丢弃连接数的差值大于0,说明又发生了丢弃连接的现象,该条件会促进连接的创建
boolean discardChanged = discardCount - lastDiscardCount > 0;
lastDiscardCount = discardCount; try {
boolean emptyWait = true; if (createError != null
&& poolingCount == 0
&& !discardChanged) {
emptyWait = false;
} if (emptyWait
&& asyncInit && createCount < initialSize) {
emptyWait = false;
} if (emptyWait) {
// 必须存在线程等待,才创建连接,否则不创建
if (poolingCount >= notEmptyWaitThreadCount
&& (!(keepAlive && activeCount + poolingCount < minIdle))
&& !isFailContinuous()
) {
empty.await(); //不需要创建连接时,阻塞(挂起)
} // 防止创建超过maxActive数量的连接
if (activeCount + poolingCount >= maxActive) {
empty.await(); //超出限制依然挂起,不再新增连接
continue;
}
} } catch (InterruptedException e) {
lastCreateError = e;
lastErrorTimeMillis = System.currentTimeMillis(); if (!closing) {
LOG.error("create connection Thread Interrupted, url: " + jdbcUrl, e);
}
break;
} finally {
lock.unlock(); //锁释放
} //从上面的程序走到这里,说明该线程被成功唤起,则进行新建连接
PhysicalConnectionInfo connection = null; try {
connection = createPhysicalConnection(); //利用驱动程序新建物理连接
} catch (SQLException e) {
LOG.error("create connection SQLException, url: " + jdbcUrl + ", errorCode " + e.getErrorCode()
+ ", state " + e.getSQLState(), e); errorCount++;
if (errorCount > connectionErrorRetryAttempts && timeBetweenConnectErrorMillis > 0) {
// fail over retry attempts
setFailContinuous(true);
if (failFast) {
lock.lock();
try {
notEmpty.signalAll();
} finally {
lock.unlock();
}
} if (breakAfterAcquireFailure) {
break;
} try {
Thread.sleep(timeBetweenConnectErrorMillis);
} catch (InterruptedException interruptEx) {
break;
}
}
} catch (RuntimeException e) {
LOG.error("create connection RuntimeException", e);
setFailContinuous(true);
continue;
} catch (Error e) {
LOG.error("create connection Error", e);
setFailContinuous(true);
break;
} if (connection == null) {
continue; //新建失败后再次尝试
} boolean result = put(connection); //尝试放入池子
if (!result) {
JdbcUtils.close(connection.getPhysicalConnection());
LOG.info("put physical connection to pool failed.");
} errorCount = 0; // reset errorCount
}
}
} //这一个put方法是上面触发接收PhysicalConnectionInfo类型连接用的,之前说过,最终保存在池子里的连接对象都是DruidConnectionHolder类型,所以这里时进行一次包装,然后真正put进去的是更下面的put方法
protected boolean put(PhysicalConnectionInfo physicalConnectionInfo) {
DruidConnectionHolder holder = null;
try {
//包装成holder类型
holder = new DruidConnectionHolder(DruidDataSource.this, physicalConnectionInfo);
} catch (SQLException ex) {
lock.lock();
try {
if (createScheduler != null) {
createTaskCount--;
}
} finally {
lock.unlock();
}
LOG.error("create connection holder error", ex);
return false;
} return put(holder); //真正放入池子
} //真正将连接对象放入池子
private boolean put(DruidConnectionHolder holder) {
lock.lock();
try {
if (poolingCount >= maxActive) {
return false; //如果此时发现当前池子里的闲置连接数已经超过了maxActive,那么就不再往里面加了
}
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-代码段-3-1的更多相关文章

  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. PlayJava Day030

    1.实例化Class类对象 //第一种,可靠高效 Class c0 = String.class ; //第二种,使用对象 Class c1 = "zhangsan".getCla ...

  2. layui 滚动加载

    直接上核心代码,其实官网介绍的很详细: var pageSize = 5;//每次请求新闻的条数 flow.load({ elem: '#newsList' //指定列表容器 ,scrollElem: ...

  3. AndroidStudio3.0升级成3.5后之前项目报错解决

    报错截图: 解决办法:在项目的build.gradle文件下加上google即可,如图:

  4. 【bzoj4671】异或图(容斥+斯特林反演+线性基)

    传送门 题意: 给出\(s,s\leq 60\)张图,每张图都有\(n,n\leq 10\)个点. 现在问有多少个图的子集,满足这些图的边"异或"起来后,这张图为连通图. 思路: ...

  5. pytorch 中改变tensor维度的几种操作

    具体示例如下,注意观察维度的变化 #coding=utf-8 import torch """改变tensor的形状的四种不同变化形式""" ...

  6. 一天两道pat(3)1007,1008

    1007没什么好说的,就是注意暴力求素数的时候,循环到(根号n)+1就好: 重点说说1008,不用新开一个数组就实现循环移位的操作 一个数组A中存有N(>0)个整数,在不允许使用另外数组的前提下 ...

  7. 用dotnet core搭建web服务器(三)ORM访问数据库

    访问传统sql数据库,大家以前都是用sql语句去查询.这些年流行orm方法 ORM是对象关系映射的简拼,就是用一个对象(class)去表示数据的一行,用对象的成员去表述数据的列 dotnet 官方很早 ...

  8. Hive 报错 Error while compiling statement: FAILED: ParseException line 1:0 character '' not supported here (state=42000,code=40000)

    Hive报错 Error while compiling statement: FAILED: ParseException line 1:0 character '' not supported h ...

  9. kaldi使用thchs30数据进行训练并执行识别操作

    操作系统 : Ubutu18.04_x64 gcc版本 :7.4.0 数据准备及训练 数据地址: http://www.openslr.org/18/ 在 egs/thchs30/s5 建立 thch ...

  10. PHP 管理树莓派

    同学给过我一块树莓派,那会儿觉得挺新鲜的.但是每次使用都需要远程桌面或者 ssh 进行登录,比较麻烦.后来为了方便管理,在树莓派上安装部署了 LAMP 环境,然后写了一个简单的 PHP 页面,代码如下 ...