【Druid源码阅读】4. 创建并运行创建连接线程:createAndStartCreatorThread()

11 篇文章 0 订阅

现在我们来一起看下 创建并运行创建连接线程: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;
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值