现在我们来一起看下 创建并运行创建连接线程:createAndStartCreatorThread();
protected void createAndStartCreatorThread() {
// 只有在创建执行器没有设置时,才会创建创建连接线程
if (createScheduler == null) {
String threadName = "Druid-ConnectionPool-Create-" + System.identityHashCode(this);
createConnectionThread = new CreateConnectionThread(threadName);
createConnectionThread.start();
return;
}
// 这里是在主线程里等待创建和销毁线程都创建完成后再继续执行
initedLatch.countDown();
}
这里有一点,也是在阿里巴巴编码规范里的,创建线程或线程池要取一个业务相关的名字,后续在排查问题时会方便很多。如果怀疑创建连接的线程意外挂掉了,可以 jstack 查看这个名字 Druid-ConnectionPool-Create- 开头的线程状态即可。
public CreateConnectionThread(String name){
super(name);
this.setDaemon(true);
}
这里可以看到,这个线程是守护线程,毕竟如果只剩下创建连接这个线程存活,也就没有意义了。
既然是线程,那主要逻辑代码肯定在 run 方法中了。
主要分两部分:
第一部分,加锁,然后使用一些 volatile 属性值做判断,是否在 empty 这个条件上等待;
第二部分,创建连接,并把连接保存到数组中;
public void run() {
initedLatch.countDown();
long lastDiscardCount = 0;
int errorCount = 0;
for (;;) {
// addLast
try {
lock.lockInterruptibly();
} catch (InterruptedException e2) {
break;
}
long discardCount = DruidDataSource.this.discardCount;
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) && (!closed)) {
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 (e) {
... // 异常处理
}
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
// 为了保证线程之间可见性,都使用了 volatile 关键字
if (closing || closed) {
break;
}
}
}