1、简介
在本文中,我们将深入了解 com.alibaba.druid.pool.DruidDataSource#init 方法中重要的两个守护线程 CreateConnectionThread 和 DestroyConnectionThread 中的 CreateConnectionThread 的相关逻辑。
2、环境
os-window10
druid-1.2.8
jdk-1.8.0_312
maven-3.8.1
复制代码
3、CreateConnectionThread 类的作用
当数据连接池中的连接不够用时会通过该线程创建物理连接并补充进连接池中,供程序使用。
4、CreateConnectionThread 类的执行流程
1、init()方法执行启动该线程
protected void createAndStartCreatorThread() {
if (createScheduler == null) {
String threadName = "Druid-ConnectionPool-Create-" + System.identityHashCode(this);
createConnectionThread = new CreateConnectionThread(threadName);
createConnectionThread.start();
return;
}
initedLatch.countDown();
}
复制代码
2、执行 CreateConnectionThread 类的 run()方法,创建物理连接前校验是否满足两个条件①必须存在线程等待,才创建连接 ②防止创建超过 maxActive 数量的连接
if (emptyWait) {
// 必须存在线程等待,才创建连接
if (poolingCount >= notEmptyWaitThreadCount //
&& (!(keepAlive && activeCount + poolingCount < minIdle))
&& !isFailContinuous()
) {
empty.await();
}
// 防止创建超过maxActive数量的连接
if (activeCount + poolingCount >= maxActive) {
empty.await();
continue;
}
}
复制代码
3、获取物理连接,获取不到则跳过本次循环
PhysicalConnectionInfo connection = null;
try {
connection = createPhysicalConnection();
}
...
if (connection == null) {
continue;
}
复制代码
4、将物理连接放入到连接池
boolean result = put(connection);
复制代码
4.1、将物理连接转换为包装类 DruidConnectionHolder
DruidConnectionHolder holder = null;
try {
holder = new DruidConnectionHolder(DruidDataSource.this, physicalConnectionInfo);
} catch (SQLException ex) {
lock.lock();
try {
if (createScheduler != null) {
clearCreateTask(physicalConnectionInfo.createTaskId);
}
} finally {
lock.unlock();
}
LOG.error("create connection holder error", ex);
return false;
}
复制代码
4.2、同步执行连接放入到连接池的逻辑,防止超过最大连接数,连接池底层为数组,会报数组越界的错误。
4.3、准备池化的连接数大于连接池的最大连接数则终止放入逻辑
if (poolingCount >= maxActive) {
if (createScheduler != null) {
clearCreateTask(createTaskId);
}
return false;
}
复制代码
4.4、连接是否与连接池中存在的连接进行判重操作
if (checkExists) {
for (int i = 0; i < poolingCount; i++) {
if (connections[i] == holder) {
return false;
}
}
}
复制代码
4.5、将连接放入到连接池中
connections[poolingCount] = holder;
复制代码
4.6、是否更新连接池连接的峰值信息
if (poolingCount > poolingPeak) {
poolingPeak = poolingCount;
poolingPeakTime = System.currentTimeMillis();
}
复制代码
5、物理连接放入连接池失败关闭物理连接
if (!result) {
JdbcUtils.close(connection.getPhysicalConnection());
LOG.info("put physical connection to pool failed.");
}
复制代码
评论