DruidDataSource类源码分析(四)

pollLast( )

核心逻辑是自旋,判断是否有可用连接,然后发送empty消息,通知生产者线程可以创建连接。之后阻塞wait。只不过这个方法需要设置超时时间。

    private DruidConnectionHolder pollLast(long nanos) throws InterruptedException, SQLException {
        // estimate超时时间
        long estimate = nanos;

        for (;;) {
            // 判断连接池可用连接poolingCount是否为0
            if (poolingCount == 0) {
                // 池子中已经没有可用的连接了,唤起添加连接的线程
                emptySignal(); // send signal to CreateThread create connection

                if (failFast && isFailContinuous()) {
                    throw new DataSourceNotAvailableException(createError);
                }

                if (estimate <= 0) {
                    waitNanosLocal.set(nanos - estimate);
                    return null;
                }

                notEmptyWaitThreadCount++;
                if (notEmptyWaitThreadCount > notEmptyWaitThreadPeak) {
                    notEmptyWaitThreadPeak = notEmptyWaitThreadCount;
                }

                try {
                    long startEstimate = estimate;
                    // 陷入等待状态,开始参与获取连接的竞争
                    // 每次唤醒时estimate会被刷新,estimate=最大阻塞时间-实际阻塞时间
                    // 下次被刷新后就是maxWait减去上次阻塞花费的实际时间
                    // 每次await的时间会逐步减少,直到归零,整体时间是约等于maxWait
                    estimate = notEmpty.awaitNanos(estimate); // signal by
                                                              // recycle or
                                                              // creator
                    notEmptyWaitCount++;
                    /**
                     * await被唤起后继续加入锁竞争,然后往下走如果发现池子里的连接数仍然是0(说明在唤醒后参与锁竞争里刚被放进来的连接又被别的线程拿去了),
                     * 则继续下一次的await,这里采用的是awaitNanos方法,初始值是maxWait,然后下次被刷新后就是maxWait减去上次阻塞花费的实际时间,
                     * 每次await的时间会逐步减少,直到归零,整体时间是约等于maxWait的,但实际比maxActive要大,
                     * 因为程序本身存在耗时以及被唤醒后又要参与锁竞争导致也存在一定的耗时。
                     */
                    notEmptyWaitNanos += (startEstimate - estimate);

                    if (!enable) {
                        connectErrorCountUpdater.incrementAndGet(this);

                        if (disableException != null) {
                            throw disableException;
                        }

                        throw new DataSourceDisableException();
                    }
                } catch (InterruptedException ie) {
                    notEmpty.signal(); // propagate to non-interrupted thread
                    notEmptySignalCount++;
                    throw ie;
                } finally {
                    notEmptyWaitThreadCount--;
                }

                if (poolingCount == 0) {
                    // 判断是否需要进行新一轮的获取连接操作
                    if (estimate > 0) {
                        continue;
                    }

                    waitNanosLocal.set(nanos - estimate);
                    return null;
                }
            }

            // poolingCount--
            decrementPoolingCount();
            // 取到最后一个连接
            DruidConnectionHolder last = connections[poolingCount];
            // 设置连接池中此连接为空(之后回归还吗?)
            connections[poolingCount] = null;

            long waitNanos = nanos - estimate;
            last.setLastNotEmptyWaitNanos(waitNanos);

            return last;
        }
    }

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值