Druid-代码段-3-1

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

 本代码段对应主流程3,新增连接的守护线程:


//DruidDataSource的内部类,对应主流程3,用来补充连接
    public class CreateConnectionThread extends Thread {

        public CreateConnectionThread(String name){
            super(name); //重置线程名称
            this.setDaemon(true); //标记为守护线程
        }

        //run方法
        public void run() {
            initedLatch.countDown(); //通知init(主流程2)自己已经启动成功

            long lastDiscardCount = 0;
            int errorCount = 0;
            for (;;) { //死循环
                // addLast
                try {
                    lock.lockInterruptibly(); //锁获取
                } catch (InterruptedException e2) {
                    break;
                }

                long discardCount = DruidDataSource.this.discardCount;
                //当前丢弃连接数与最后一次丢弃连接数的差值大于0,说明又发生了丢弃连接的现象,该条件会促进连接的创建
                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) {
                        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 (RuntimeException e) {
                    LOG.error("create connection RuntimeException", e);
                    setFailContinuous(true);
                    continue;
                } catch (Error e) {
                    LOG.error("create connection Error", e);
                    setFailContinuous(true);
                    break;
                }

                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
            }
        }
    }



    //这一个put方法是上面触发接收PhysicalConnectionInfo类型连接用的,之前说过,最终保存在池子里的连接对象都是DruidConnectionHolder类型,所以这里时进行一次包装,然后真正put进去的是更下面的put方法
    protected boolean put(PhysicalConnectionInfo physicalConnectionInfo) {
        DruidConnectionHolder holder = null;
        try {
            //包装成holder类型
            holder = new DruidConnectionHolder(DruidDataSource.this, physicalConnectionInfo);
        } catch (SQLException ex) {
            lock.lock();
            try {
                if (createScheduler != null) {
                    createTaskCount--;
                }
            } finally {
                lock.unlock();
            }
            LOG.error("create connection holder error", ex);
            return false;
        }

        return put(holder); //真正放入池子
    }


    //真正将连接对象放入池子
    private boolean put(DruidConnectionHolder holder) {
        lock.lock();
        try {
            if (poolingCount >= maxActive) {
                return false; //如果此时发现当前池子里的闲置连接数已经超过了maxActive,那么就不再往里面加了
            }
            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 13:10  是胖虎捏  阅读(453)  评论(0编辑  收藏  举报