Druid-代码段-4-2

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

 本代码段对应流程4.1,连接池瘦身:


//连接池瘦身
    public void shrink(boolean checkTime, boolean keepAlive) {
        try {
            lock.lockInterruptibly();
        } catch (InterruptedException e) {
            return;
        }

        int evictCount = 0;
        int keepAliveCount = 0;
        try {
            if (!inited) {
                return;
            }

            final int checkCount = poolingCount - minIdle; //根据poolingCount和minIdle计算出evictCheck的范围
            final long currentTimeMillis = System.currentTimeMillis();
            for (int i = 0; i < poolingCount; ++i) { //开始遍历连接池里闲置的连接
                DruidConnectionHolder connection = connections[i];

                if (checkTime) { //除非手动调用,不然经过主流程4触发,一般为true
                    if (phyTimeoutMillis > 0) { //默认不启用,忽略
                        long phyConnectTimeMillis = currentTimeMillis - connection.connectTimeMillis;
                        if (phyConnectTimeMillis > phyTimeoutMillis) {
                            evictConnections[evictCount++] = connection;
                            continue;
                        }
                    }

                    //计算闲置时间
                    long idleMillis = currentTimeMillis - connection.lastActiveTimeMillis;

                    if (idleMillis < minEvictableIdleTimeMillis
                            && idleMillis < keepAliveBetweenTimeMillis
                    ) { //如果闲置时间达不到检测&瘦身的阈值,则不处理
                        break;
                    }

                    if (idleMillis >= minEvictableIdleTimeMillis) {
                        if (checkTime && i < checkCount) { //达到需要丢弃的阈值时,则判断连接下标是否在evictCheck范围,若在,则视为“可以丢弃的对象”放入evictConnections数组
                            evictConnections[evictCount++] = connection;
                            continue;
                        } else if (idleMillis > maxEvictableIdleTimeMillis) { //达到必须要丢弃的阈值时,则不管是不是在evictCheck范围内,都直接放入“可以丢弃的对象”的evictConnections数组
                            evictConnections[evictCount++] = connection;
                            continue;
                        }
                    }

                    //如果上面的条件均没有命中,如果keepAlive为true,则判断是不是超过了闲置连接检查其活性的频次阈值(即由keepAliveBetweenTimeMillis控制)
                    if (keepAlive && idleMillis >= keepAliveBetweenTimeMillis) {
                        keepAliveConnections[keepAliveCount++] = connection; //满足条件则视为“需要检测活性的对象”,放入keepAliveConnections数组
                    }
                } else {
                    if (i < checkCount) {
                        evictConnections[evictCount++] = connection;
                    } else {
                        break;
                    }
                }
            }

            int removeCount = evictCount + keepAliveCount; //这一批需要移除特殊处理的连接总数
            if (removeCount > 0) {
                System.arraycopy(connections, removeCount, connections, 0, poolingCount - removeCount); //根据当前移除的元素,把剩余的元素移动至数组首部(参考流程4.1)
                Arrays.fill(connections, poolingCount - removeCount, poolingCount, null); //剩余位置清空
                poolingCount -= removeCount;
            }
            keepAliveCheckCount += keepAliveCount;
        } finally {
            lock.unlock();
        }

        if (evictCount > 0) { //如果需要丢弃的连接数量大于0
            for (int i = 0; i < evictCount; ++i) {
                DruidConnectionHolder item = evictConnections[i];
                Connection connection = item.getConnection();
                JdbcUtils.close(connection); //直接关闭连接(这里是直接关闭驱动连接,不再放回池子)
                destroyCountUpdater.incrementAndGet(this);
            }
            Arrays.fill(evictConnections, null); //将evictConnections数组重新置空(方便下次使用)
        }

        if (keepAliveCount > 0) { //检测那些需要判活的连接数
            // keep order
            for (int i = keepAliveCount - 1; i >= 0; --i) {
                DruidConnectionHolder holer = keepAliveConnections[i];
                Connection connection = holer.getConnection();
                holer.incrementKeepAliveCheckCount();

                boolean validate = false;
                try {
                    this.validateConnection(connection); //检测其活性
                    validate = true;
                } catch (Throwable error) {
                    if (LOG.isDebugEnabled()) {
                        LOG.debug("keepAliveErr", error);
                    }
                    // skip
                }

                boolean discard = !validate;
                if (validate) { //检测通过
                    holer.lastKeepTimeMillis = System.currentTimeMillis();
                    boolean putOk = put(holer); //检测通过后,再次放入池子
                    if (!putOk) { //放不进去池子(说明已经达到连接池最大连接数阈值maxActive),则视为可以“直接抛弃”的连接
                        discard = true;
                    }
                }

                if (discard) {
                    try {
                        connection.close(); //如果可以抛弃,则直接关闭连接(直接调用驱动的close)
                    } catch (Exception e) {
                        // skip
                    }

                    lock.lock();
                    try {
                        discardCount++; //抛弃连接数累加

                        if (activeCount <= minIdle) {
                            emptySignal(); //唤起主流程3追加连接对象
                        }
                    } finally {
                        lock.unlock();
                    }
                }
            }
            this.getDataSourceStat().addKeepAliveCheckCount(keepAliveCount);
            Arrays.fill(keepAliveConnections, null); //将keepAliveConnections数组重新置空(方便下次使用)
        }
    }

    //上面检测通过,再次通过该方法重新把连接放入池子
    private boolean put(DruidConnectionHolder holder) {
        lock.lock();
        try {
            if (poolingCount >= maxActive) {
                return false; //若池子内闲置连接数超过maxActive,则无法继续添加新的连接进来,返回false
            }
            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;
    }
posted @ 2019-09-21 19:57  是胖虎捏  阅读(515)  评论(0编辑  收藏  举报