Druid源码阅读系列(四)

DruidDataSourceinit()方法虽说只是初始化,将初始的连接创建,放到连接池里,供应用调用。但它不仅仅只有连接的初始化,还有一些需要一直运行或者周期性执行的任务初始化,我们来看一下这块的实现。

public void init() throws SQLException {
        if (inited) {
            return;
        }
        、、、、、、、、、、、、、、、、、省略
        createAndLogThread();
        createAndStartCreatorThread();
        createAndStartDestroyThread();
        、、、、、、、、、、、、、、、、、、省略
        }

他们实现主要在这三个createXXX()里面,首先看看第一个,从名字可以看出是日志相关的Thread,内部实现如下:

    private void createAndLogThread() {
        if (this.timeBetweenLogStatsMillis <= 0) {
            return;
        }

        String threadName = "Druid-ConnectionPool-Log-" + System.identityHashCode(this);
        logStatsThread = new LogStatsThread(threadName);
        logStatsThread.start();

        this.resetStatEnable = false;
    }

这个线程只有设置了timeBetweenLogStatsMillis时间之后才会生效,会周期性的进行日志记录,关键代码是这个:

public DruidDataSourceStatValue getStatValueAndReset() {
    DruidDataSourceStatValue value = new DruidDataSourceStatValue();

    lock.lock();
    try {
        value.setPoolingCount(this.poolingCount);
        value.setPoolingPeak(this.poolingPeak);
        value.setPoolingPeakTime(this.poolingPeakTime);

        value.setActiveCount(this.activeCount);
        value.setActivePeak(this.activePeak);
        value.setActivePeakTime(this.activePeakTime);

        value.setConnectCount(this.connectCount);
        value.setCloseCount(this.closeCount);
        value.setWaitThreadCount(lock.getWaitQueueLength(notEmpty));
        value.setNotEmptyWaitCount(this.notEmptyWaitCount);
        value.setNotEmptyWaitNanos(this.notEmptyWaitNanos);
        value.setKeepAliveCheckCount(this.keepAliveCheckCount);

        // reset
        this.poolingPeak = 0;
        this.poolingPeakTime = 0;
        this.activePeak = 0;
        this.activePeakTime = 0;
        this.connectCount = 0;
        this.closeCount = 0;
        this.keepAliveCheckCount = 0;

        this.notEmptyWaitCount = 0;
        this.notEmptyWaitNanos = 0;
    } finally {
        lock.unlock();
    }

会将各种当前的数据写到DruidDataSourceStatValue对象里,然后去重置数据,并将日志输出。

注意这是一个守护线程,其优点是当jvm结束的时候,不需要等待线程结束。整个程序关闭对线程是毫无依赖的。

接下来是createAndStartCreatorThread()方法,它主要用来创建线程,分为两种情况:

异步创建

当用户设置了createScheduler(异步)时,这个方法其实什么都不会做,只是对initedLatch减一。

protected void createAndStartCreatorThread() {
    if (createScheduler == null) {//只针对没有设置createScheduler的情况生效
        String threadName = "Druid-ConnectionPool-Create-" + System.identityHashCode(this);
        createConnectionThread = new CreateConnectionThread(threadName);
        createConnectionThread.start();
        return;
    }

    initedLatch.countDown();
}

那异步情况下主要通过createScheduler周期性的去创建连接,创建连接代码在CreateConnectionTaskrunInternal()方法里,这块代码里面有很多逻辑判断,包括尝试重连的代码也在里面

if (emptyWait) {
    // 必须存在线程等待,才创建连接
    if (poolingCount >= notEmptyWaitThreadCount //
            && (!(keepAlive && activeCount + poolingCount < minIdle)) // 在keepAlive场景不能放弃创建
            && (!initTask) // 线程池初始化时的任务不能放弃创建
            && !isFailContinuous() // failContinuous时不能放弃创建,否则会无法创建线程
            && !isOnFatalError() // onFatalError时不能放弃创建,否则会无法创建线程
    ) {
        clearCreateTask(taskId);
        return;
    }

    // 防止创建超过maxActive数量的连接
    if (activeCount + poolingCount >= maxActive) {
        clearCreateTask(taskId);
        return;
    }
}

只有当通过上述条件时,才会进行连接创建。

同步创建

同步代码核心在CreateConnectionThreadrun()方法里,注意这里的CreateConnectionThread是个守护线程,如果程序关闭它是不会在执行的。

if (emptyWait) {
    // 必须存在线程等待,才创建连接
    if (poolingCount >= notEmptyWaitThreadCount //
            && (!(keepAlive && activeCount + poolingCount < minIdle))
            && !isFailContinuous()
    ) {
        empty.await();
    }

    // 防止创建超过maxActive数量的连接
    if (activeCount + poolingCount >= maxActive) {
        empty.await();
        continue;
    }
}

细心的朋友应该看出来了,同步和异步这两块代码十分类似,只是同步的判断会比异步少一点,异步情况会复杂点。然后同步和异步的线程名字其实很类似,只是后缀不一样而已,同步是Thread后缀,异步是Task后缀。一般线程池都是用的task,可能和这种命名习惯有关。

createAndStartDestroyThread()的实现相对复杂点,会有收缩和连接丢弃,保活等逻辑,我们明天继续。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值