common-pool2 (三)------ 链接池实现详解

GenericObjectPool是用来作为链接池实现的,用来和PooledObjectFactory组合使用可以对外提供一个健壮的链接池。

基本参数

    //最大空闲链接
    private volatile int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE;
    //最小空闲链接
    private volatile int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE;
    //对象生成工厂
    private final PooledObjectFactory factory;
    //对象总数 < 配置的最大链接数
    private final Map, PooledObject> allObjects =
            new ConcurrentHashMap<>();
    //已创建对象总数
    private final AtomicLong createCount = new AtomicLong(0);
    //调用创建方法的总线程数
    private long makeObjectCount = 0;
    //makeObjectCount 增长时的锁
    private final Object makeObjectCountLock = new Object();
    //空闲对象队列
    private final LinkedBlockingDeque> idleObjects;

构造函数

1. 基础构造函数

    public GenericObjectPool(final PooledObjectFactory factory,
                             final GenericObjectPoolConfig config) {

        super(config, ONAME_BASE, config.getJmxNamePrefix());

        if (factory == null) {
            jmxUnregister(); // tidy up
            throw new IllegalArgumentException("factory may not be null");
        }
        //赋值自定义的PooledObjectFactory实现对象
        this.factory = factory;
        //LinkedBlockingDeque用来维护对象池,是一个双端队列
        idleObjects = new LinkedBlockingDeque<>(config.getFairness());
        //设置外部动态配置参数,主要需要覆盖BaseGenericObjectPool内的参数
        setConfig(config);
        //设置回收线程【主要针对空闲对象和泄露对象的回收】
        startEvictor(getTimeBetweenEvictionRunsMillis());
    }

2.带丢弃策略的构造函数

    public GenericObjectPool(final PooledObjectFactory factory,
                             final GenericObjectPoolConfig config, final AbandonedConfig abandonedConfig) {
        //调用上述构造函数
        this(factory, config);
        //增加丢弃策略的配置
        setAbandonedConfig(abandonedConfig);
    }

借取对象方法borrowObject

1. 从链接池内获取一个新链接

public T borrowObject(final long borrowMaxWaitMillis) throws Exception {
        //判断链接池是否打开
        assertOpen();

        //是否执行回收逻辑【长时间占用链接而没有释放的链接】
        //1.removeAbandonedOnBorrow = true【默认为false】
        //2.空闲链接数目 < 2
        //3.(当前总链接数 - 池内链接数) > 配置的最大链接数 - 3
        final AbandonedConfig ac = this.abandonedConfig;
        if (ac != null && ac.getRemoveAbandonedOnBorrow() &&
                (getNumIdle() < 2) &&
                (getNumActive() > getMaxTotal() - 3) ) {
            removeAbandoned(ac);
        }

        PooledObject p = null;
        //获取不到链接时是否阻塞直到成功获取
        final boolean blockWhenExhausted = getBlockWhenExhausted();
        //新建标识
        boolean create;
        //借取链接时花费时间
        final long waitTime = System.currentTimeMillis();

        while (p == null) {
            create = false;
            //从链接池内获取一个空闲链接
            p = idleObjects.pollFirst();
            if (p == null) {
                //如果链接池内获取不到,则创建一个新链接
                //1.创建成功
                //2.创建失败【已经达到最大链接数目,当前没法继续创建,返回null】
                p = create();
                if (p != null) {
                    //更新创建标识,表明创建成功
                    create = true;
                }
            }
            //获取不到链接则阻塞等待
            if (blockWhenExhausted) {
                if (p == null) {
                    if (borrowMaxWaitMillis < 0) {
                        //没有超时时间,则阻塞到能获取到新链接为止
                        p = idleObjects.takeFirst();
                    } else {
                        //有超时时间
                        p = idleObjects.pollFirst(borrowMaxWaitMillis,
                                TimeUnit.MILLISECONDS);
                    }
                }
                //达到超时时间,则time out
                if (p == null) {
                    throw new NoSuchElementException(
                            "Timeout waiting for idle object");
                }
            } else {
                //没有阻塞时间,则抛出异常
                if (p == null) {
                    throw new NoSuchElementException("Pool exhausted");
                }
            }
            //更新链接的状态,变为占用
            if (!p.allocate()) {
                p = null;
            }

            if (p != null) {
                try {
                    //尝试激活链接,需要子类自己实现自己的激活流程
                    factory.activateObject(p);
                } catch (final Exception e) {
                    try {
                        //激活失败,则销毁当前无效链接
                        destroy(p);
                    } catch (final Exception e1) {
                        // Ignore - activation failure is more important
                    }
                    p = null;
                    if (create) {
                        //当前链接是新建出来的,则抛出异常,如果是从池内拿到的,无需判断
                        final NoSuchElementException nsee = new NoSuchElementException(
                                "Unable to activate object");
                        nsee.initCause(e);
                        throw nsee;
                    }
                }
                //1.借取时是否进行测试
                //2.新建的是否进行测试
                if (p != null && (getTestOnBorrow() || create && getTestOnCreate())) {
                    boolean validate = false;
                    Throwable validationThrowable = null;
                    try {
                        //校验链接,主要判断链接状态是否正常
                        validate = factory.validateObject(p);
                    } catch (final Throwable t) {
                        PoolUtils.checkRethrow(t);
                        validationThrowable = t;
                    }
                    if (!validate) {
                        try {
                            //不正常销毁
                            destroy(p);
                            destroyedByBorrowValidationCount.incrementAndGet();
                        } catch (final Exception e) {
                            // Ignore - validation failure is more important
                        }
                        p = null;
                        if (create) {
                            final NoSuchElementException nsee = new NoSuchElementException(
                                    "Unable to validate object");
                            nsee.initCause(validationThrowable);
                            throw nsee;
                        }
                    }
                }
            }
        }

        //更新此链接的一些统计信息
        updateStatsBorrow(p, System.currentTimeMillis() - waitTime);

        return p.getObject();
    }

2.create()创建对象的方法

    private PooledObject create() throws Exception {
        //配置的最大链接数
        int localMaxTotal = getMaxTotal();
        if (localMaxTotal < 0) {
            localMaxTotal = Integer.MAX_VALUE;
        }
        //是否创建成功的一个flag
        // - TRUE:  调用工厂类成功创建一个对象
        // - FALSE: 返回空
        // - null:  并发创建标识
        Boolean create = null;
        while (create == null) {
            synchronized (makeObjectCountLock) {
                //获取包括当前一次操作创建出的总链接数
                final long newCreateCount = createCount.incrementAndGet();
                if (newCreateCount > localMaxTotal) {
                    //表明当前容量已满,针对当前一次操作需要做特殊处理
                    //数目记录减一
                    createCount.decrementAndGet();
                    if (makeObjectCount == 0) {
                        //容量已满并且没有其他线程在创建连接对象,
                        //表明此次已经无法创建,返回null并等待归还的空闲对象
                        create = Boolean.FALSE;
                    } else {
                        //表明当前有其他线程已经在创建对象最后一个连接对象
                        //如果此次继续创建的话可能会超过容量大小,但是此时不能返回false,因为其他线程已经在创建了
                        //其他线程创建结果是未知的,因此阻塞当前线程,等待其他线程的唤醒
                        //唤醒之后,会继续进入while逻辑,进行下一次创建流程
                        makeObjectCountLock.wait();
                    }
                } else {
                    //当前数目没有超过最大连接数,则可以创建
                    makeObjectCount++;
                    create = Boolean.TRUE;
                }
            }
        }

        if (!create.booleanValue()) {
            //此条件只在容量已满时返回null,用于等待线程归还
            return null;
        }

        final PooledObject p;
        try {
            //创建连接对象
            p = factory.makeObject();
        } catch (final Exception e) {
            //发生异常时数目减一
            createCount.decrementAndGet();
            throw e;
        } finally {
            synchronized (makeObjectCountLock) {
                makeObjectCount--;
                makeObjectCountLock.notifyAll();
            }
        }

        final AbandonedConfig ac = this.abandonedConfig;
        if (ac != null && ac.getLogAbandoned()) {
            p.setLogAbandoned(true);
            if (p instanceof DefaultPooledObject) {
                ((DefaultPooledObject) p).setRequireFullStackTrace(ac.getRequireFullStackTrace());
            }
        }
        //计数
        createdCount.incrementAndGet();
        allObjects.put(new IdentityWrapper<>(p.getObject()), p);
        return p;
    }

归还对象方法returnObject

1.归还一个对象至连接池

    public void returnObject(final T obj) {

        final PooledObject p = allObjects.get(new IdentityWrapper<>(obj));

        //1.当前连接对象不是连接池对象
        //2.当前连接已经被丢弃
        if (p == null) {
            if (!isAbandonedConfig()) {
                throw new IllegalStateException(
                        "Returned object not currently part of this pool");
            }
            return;
        }

        synchronized(p) {
            final PooledObjectState state = p.getState();
            //此连接对象不是已分配状态,抛异常
            if (state != PooledObjectState.ALLOCATED) {
                throw new IllegalStateException(
                        "Object has already been returned to this pool or is invalid");
            }
            //标记为returning,避免被垃圾回收器标记为丢弃状态
            p.markReturning();
        }
        //
        final long activeTime = p.getActiveTimeMillis();
        //是否在归还时测试连接对象
        if (getTestOnReturn()) {
            if (!factory.validateObject(p)) {
                try {
                    //验证不通过销毁对象
                    destroy(p);
                } catch (final Exception e) {
                    swallowException(e);
                }
                try {
                    //确保最小空闲数量
                    ensureIdle(1, false);
                } catch (final Exception e) {
                    swallowException(e);
                }
                //更新归还的统计信息
                updateStatsReturn(activeTime);
                return;
            }
        }

        try {
            factory.passivateObject(p);
        } catch (final Exception e1) {
            swallowException(e1);
            try {
                destroy(p);
            } catch (final Exception e) {
                swallowException(e);
            }
            try {
                ensureIdle(1, false);
            } catch (final Exception e) {
                swallowException(e);
            }
            updateStatsReturn(activeTime);
            return;
        }

        if (!p.deallocate()) {
            //变更状态
            throw new IllegalStateException(
                    "Object has already been returned to this pool or is invalid");
        }
        //获取最大空闲数量
        final int maxIdleSave = getMaxIdle();
        if (isClosed() || maxIdleSave > -1 && maxIdleSave <= idleObjects.size()) {
            //1.连接池已关闭
            //2.当前连接池空闲对象已满
            //则无需归还
            try {
                destroy(p);
            } catch (final Exception e) {
                swallowException(e);
            }
        } else {
            //根据配置的入队列规则讲连接对象放入队列内
            if (getLifo()) {
                idleObjects.addFirst(p);
            } else {
                idleObjects.addLast(p);
            }
            if (isClosed()) {
                // Pool closed while object was being added to idle objects.
                // Make sure the returned object is destroyed rather than left
                // in the idle object pool (which would effectively be a leak)
                clear();
            }
        }
        updateStatsReturn(activeTime);
    }

2. ensureIdle()确保最小连接

    private void ensureIdle(final int idleCount, final boolean always) throws Exception {
        if (idleCount < 1 || isClosed() || (!always && !idleObjects.hasTakeWaiters())) {
            //如果连接池此时有一个线程在等待获取,则由此线程保证即可
            return;
        }
        //当池内对象 p = create();
            if (p == null) {
                // Can't create objects, no reason to think another call to
                // create will work. Give up.
                break;
            }
            if (getLifo()) {
                idleObjects.addFirst(p);
            } else {
                idleObjects.addLast(p);
            }
        }
        if (isClosed()) {
            clear();
        }
    }

对象回收定时器

1.evict()是空闲队列回收器或者泄露对象回收器

   public void evict() throws Exception {
        assertOpen();

        if (idleObjects.size() > 0) {

            PooledObject underTest = null;
            final EvictionPolicy evictionPolicy = getEvictionPolicy();

            synchronized (evictionLock) {
                //获取回收期执行参数
                final EvictionConfig evictionConfig = new EvictionConfig(
                        getMinEvictableIdleTimeMillis(),
                        getSoftMinEvictableIdleTimeMillis(),
                        getMinIdle());
                //连接是否被此回收器检测
                final boolean testWhileIdle = getTestWhileIdle();
                //getNumTests 为一次检测几个对象,默认为3
                for (int i = 0, m = getNumTests(); i < m; i++) {
                    //构造一个迭代器
                    if (evictionIterator == null || !evictionIterator.hasNext()) {
                        evictionIterator = new EvictionIterator(idleObjects);
                    }
                    if (!evictionIterator.hasNext()) {
                        return;
                    }

                    try {
                        underTest = evictionIterator.next();
                    } catch (final NoSuchElementException nsee) {
                       //检测时碰巧被借出,无需检测了
                        i--;
                        evictionIterator = null;
                        continue;
                    }

                    if (!underTest.startEvictionTest()) {
                        //判定此连接对象能否被检测,状态不是IDLE的不检测
                        i--;
                        continue;
                    }
                    boolean evict;
                    try {
                        //根据回收策略判断对象是否能够被回收
                        evict = evictionPolicy.evict(evictionConfig, underTest,
                                idleObjects.size());
                    } catch (final Throwable t) {
                        PoolUtils.checkRethrow(t);
                        swallowException(new Exception(t));
                        evict = false;
                    }

                    if (evict) {
                        //能够回收时销毁此对象
                        destroy(underTest);
                        destroyedByEvictorCount.incrementAndGet();
                    } else {
                        //没法回收时去检测
                        if (testWhileIdle) {
                            boolean active = false;
                            try {
                                //激活对象
                                factory.activateObject(underTest);
                                active = true;
                            } catch (final Exception e) {
                                //激活失败销毁
                                destroy(underTest);
                                destroyedByEvictorCount.incrementAndGet();
                            }
                            if (active) {
                                //激活之后验证此连接是否正常
                                if (!factory.validateObject(underTest)) {
                                    //验证失败销毁
                                    destroy(underTest);
                                    destroyedByEvictorCount.incrementAndGet();
                                } else {
                                    try {
                                        factory.passivateObject(underTest);
                                    } catch (final Exception e) {
                                        destroy(underTest);
                                        destroyedByEvictorCount.incrementAndGet();
                                    }
                                }
                            }
                        }
                        if (!underTest.endEvictionTest(idleObjects)) {
                        }
                    }
                }
            }
        }
        //回收对象时判定是否需要回收占用对象【避免占用时间过长导致连接泄露】
        final AbandonedConfig ac = this.abandonedConfig;
        if (ac != null && ac.getRemoveAbandonedOnMaintenance()) {
            removeAbandoned(ac);
        }
    }

2.evict()方法

 EvictionConfig{
        //空闲链接存活的最小时间,达到此值后空闲链接将被移除
        private final long idleEvictTime;
        //空闲链接存活的最小时间,达到此值后被移除,且要保留minIlde个空闲链接,默认为-1。
        private final long idleSoftEvictTime;
        //最小空闲连接
        private final int minIdle;
    }

    public boolean evict(final EvictionConfig config, final PooledObject underTest,
                         final int idleCount) {
        //1.空闲连接的生成时间 > 配置的存活最小时间
        //2.连接池大小 > 最小空闲连接  或者  空闲连接的生成时间 > 配置存活的最小时间
        if ((config.getIdleSoftEvictTime() < underTest.getIdleTimeMillis() &&
                config.getMinIdle() < idleCount) ||
                config.getIdleEvictTime() < underTest.getIdleTimeMillis()) {
            return true;
        }
        return false;
    }

3.removeAbandoned() 回收泄露对象

    private void removeAbandoned(final AbandonedConfig ac) {
        final long now = System.currentTimeMillis();
        //配置回收过程的超时时间
        final long timeout =
                now - (ac.getRemoveAbandonedTimeout() * 1000L);
        final ArrayList> remove = new ArrayList<>();
        final Iterator> it = allObjects.values().iterator();
        while (it.hasNext()) {
            final PooledObject pooledObject = it.next();
            synchronized (pooledObject) {
                if (pooledObject.getState() == PooledObjectState.ALLOCATED &&
                        pooledObject.getLastUsedTime() <= timeout) {
                    //连接对象被占用时间过长,标记为回收
                    pooledObject.markAbandoned();
                    remove.add(pooledObject);
                }
            }
        }

        final Iterator> itr = remove.iterator();
        while (itr.hasNext()) {
            final PooledObject pooledObject = itr.next();
            if (ac.getLogAbandoned()) {
                pooledObject.printStackTrace(ac.getLogWriter());
            }
            try {
                //销毁对象
                invalidateObject(pooledObject.getObject());
            } catch (final Exception e) {
                e.printStackTrace();
            }
        }
    }

 

你可能感兴趣的:(连接池)