Apache Commons-pool源碼分析

之前學(xué)習(xí)了一下Jedis的操作原理和JedisPool的相關(guān)實(shí)現(xiàn),但是在JedisPool的實(shí)現(xiàn)中對于JedisPool的連接池實(shí)現(xiàn)沒有深入的學(xué)習(xí),因?yàn)镴edisPool的連接池的實(shí)現(xiàn)是基于Apache Commons-pool的,所以只要重點(diǎn)關(guān)注Apache Commons-pool就OK了,之前在看Mybatis的連接池的實(shí)現(xiàn)時(shí)候有關(guān)注DBCP的連接池的實(shí)現(xiàn),DBCP的連接池就是靠Apache Commons-pool來支撐的,所以這里也算是把DBCP底層的連接池也學(xué)習(xí)了一下。

Apache Commons-pool是一個(gè)Apache組織開源的對象池。我們所熟知的基本上就是DBCP和JedisPool了。對于這種“池”的概念A(yù)pache Commons-pool做了很好的支撐,也能盡量的將使用方和對象池本身做一個(gè)很好的解耦。目前Apache Commons-pool托管在github上,地址是:

Apache Commons-pool整體的代碼結(jié)構(gòu)并不復(fù)雜,下面是代碼結(jié)構(gòu):

Paste_Image.png

主要關(guān)鍵的類都在pool2包下,impl里面是一些默認(rèn)的實(shí)現(xiàn),proxy是提供的一些代理的支持。

對于用過JedisPool的童鞋來說呢,對于一個(gè)類一定不陌生,那就是GenericObjectPoolConfig,最開始用的時(shí)候我也是被各種參數(shù)弄得暈頭轉(zhuǎn)向,歸根結(jié)底還是對pool的概念的模糊。本文的目的就是弄懂原理,弄清楚各個(gè)參數(shù)都是干嘛用的。
首先看一些關(guān)鍵的參數(shù)和說明吧:

lifo:對象池存儲空閑對象是使用的LinkedBlockingDeque,它本質(zhì)上是一個(gè)支持FIFO和FILO的雙向的隊(duì)列,common-pool2中的LinkedBlockingDeque不是Java原生的隊(duì)列,而有common-pool2重新寫的一個(gè)雙向隊(duì)列。如果為true,表示使用FIFO獲取對象。默認(rèn)值是true.建議使用默認(rèn)值。

fairness:common-pool2實(shí)現(xiàn)的LinkedBlockingDeque雙向阻塞隊(duì)列使用的是Lock鎖。這個(gè)參數(shù)就是表示在實(shí)例化一個(gè)LinkedBlockingDeque時(shí),是否使用lock的公平鎖。默認(rèn)值是false,建議使用默認(rèn)值。

maxWaitMillis:當(dāng)沒有空閑連接時(shí),獲取一個(gè)對象的最大等待時(shí)間。如果這個(gè)值小于0,則永不超時(shí),一直等待,直到有空閑對象到來。如果大于0,則等待maxWaitMillis長時(shí)間,如果沒有空閑對象,將拋出NoSuchElementException異常。默認(rèn)值是-1;可以根據(jù)需要自己調(diào)整,單位是毫秒。

minEvictableIdleTimeMillis:對象最小的空閑時(shí)間。如果為小于等于0,最Long的最大值,如果大于0,當(dāng)空閑的時(shí)間大于這個(gè)值時(shí),執(zhí)行移除這個(gè)對象操作。默認(rèn)值是1000L * 60L * 30L;即30分鐘。這個(gè)參數(shù)是強(qiáng)制性的,只要空閑時(shí)間超過這個(gè)值,就會移除。

softMinEvictableIdleTimeMillis:對象最小的空間時(shí)間,如果小于等于0,取Long的最大值,如果大于0,當(dāng)對象的空閑時(shí)間超過這個(gè)值,并且當(dāng)前空閑對象的數(shù)量大于最小空閑數(shù)量(minIdle)時(shí),執(zhí)行移除操作。這個(gè)和上面的minEvictableIdleTimeMillis的區(qū)別是,它會保留最小的空閑對象數(shù)量。而上面的不會,是強(qiáng)制性移除的。默認(rèn)值是-1;

numTestsPerEvictionRun:檢測空閑對象線程每次檢測的空閑對象的數(shù)量。默認(rèn)值是3;如果這個(gè)值小于0,則每次檢測的空閑對象數(shù)量等于當(dāng)前空閑對象數(shù)量除以這個(gè)值的絕對值,并對結(jié)果向上取整。

testOnCreate:在創(chuàng)建對象時(shí)檢測對象是否有效,true是,默認(rèn)值是false。

testOnBorrow:在從對象池獲取對象時(shí)是否檢測對象有效,true是;默認(rèn)值是false。

testOnReturn:在向?qū)ο蟪刂袣w還對象時(shí)是否檢測對象有效,true是,默認(rèn)值是false。

testWhileIdle:在檢測空閑對象線程檢測到對象不需要移除時(shí),是否檢測對象的有效性。true是,默認(rèn)值是false。

timeBetweenEvictionRunsMillis:空閑對象檢測線程的執(zhí)行周期,即多長時(shí)候執(zhí)行一次空閑對象檢測。單位是毫秒數(shù)。如果小于等于0,則不執(zhí)行檢測線程。默認(rèn)值是-1;

blockWhenExhausted:當(dāng)對象池沒有空閑對象時(shí),新的獲取對象的請求是否阻塞。true阻塞。默認(rèn)值是true;

maxTotal:對象池中管理的最多對象個(gè)數(shù)。默認(rèn)值是8。

maxIdle:對象池中最大的空閑對象個(gè)數(shù)。默認(rèn)值是8。

minIdle:對象池中最小的空閑對象個(gè)數(shù)。默認(rèn)值是0。

其實(shí)光看參數(shù),根本看不出它們都是做什么的,所以我們還是開始看代碼,我們主要關(guān)注的類是GenericObjectPool,雖然Commons-pool提供了基于key的Object的緩存池,但是我們不常用:

GenericObjectPool的UML類圖如下:

Paste_Image.png

其中GenericObjectPool繼承了BaseGenericObjectPool,實(shí)現(xiàn)了ObjectPool、GenericObjectPoolMXBean等接口,并且提供了泛型T來指定緩存對象的類型。
BaseGenericObjectPool中主要做了一些公共的實(shí)現(xiàn),GenericObjectPool則是復(fù)寫一些抽象方法,做具體的實(shí)現(xiàn),GenericObjectPoolMXBean主要做一些JMX的監(jiān)控。

    /**
     * Create a new <code>GenericObjectPool</code> using defaults from
     * {@link GenericObjectPoolConfig}.
     *
     * @param factory The object factory to be used to create object instances
     *                used by this pool
     */
    public GenericObjectPool(final PooledObjectFactory<T> factory) {
        this(factory, new GenericObjectPoolConfig());
    }
    /**
     * Create a new <code>GenericObjectPool</code> using a specific
     * configuration.
     *
     *
     * factory用來給對象池創(chuàng)建對象
     * @param factory   The object factory to be used to create object instances
     *                  used by this pool
     *
     * 對相應(yīng)的對象池進(jìn)行配置
     * @param config    The configuration to use for this pool instance. The
     *                  configuration is used by value. Subsequent changes to
     *                  the configuration object will not be reflected in the
     *                  pool.
     */
    public GenericObjectPool(final PooledObjectFactory<T> factory,
            final GenericObjectPoolConfig config) {

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

        if (factory == null) {
            jmxUnregister(); // tidy up
            throw new IllegalArgumentException("factory may not be null");
        }

        this.factory = factory;
        //初始化空閑對象池,傳入鎖的模式,公平還是非公平
        idleObjects = new LinkedBlockingDeque<PooledObject<T>>(config.getFairness());
        //參數(shù)設(shè)置
        setConfig(config);
        //開啟淘汰機(jī)制,timeBetweenEvictionRunsMillis為淘汰的間隔
        startEvictor(getTimeBetweenEvictionRunsMillis());
    }

這里比較關(guān)鍵的就是PooledObjectFactory,PooledObjectFactory是外部使用對象池的使用者需要實(shí)現(xiàn)的關(guān)于待緩存的對象的創(chuàng)建、激活銷毀等一系列操作的工廠。這也充分體現(xiàn)了“解耦”的思想,自己的東西自己管,很合理。

主要方法如下:
makeObject為創(chuàng)建對象的方法。
destroyObject為銷毀對象的方法。
validateObject為校驗(yàn)對象有消息的方法。
activateObject為激活對象的方法。
passivateObject為鈍化對象的方法。

其實(shí)就是在創(chuàng)建對象的時(shí)候利用Factoty的makeObject來創(chuàng)建,銷毀的時(shí)候利用destroyObject來銷毀.....

接下來呢創(chuàng)建了一個(gè)雙端隊(duì)列LinkedBlockingDeque作為idle隊(duì)列緩存所有空閑的對象,顯然是無界的,那么大小就需要外部去控制。這里有一個(gè)點(diǎn)就是BlockingDeque的鎖競爭,默認(rèn)是非公平的鎖,這也是JDK默認(rèn)選擇的鎖。吞吐量很重要哦。
fairness就是鎖的類型。

接下來開啟一個(gè)TimeTask對idle隊(duì)列進(jìn)行定時(shí)的掃描,必要時(shí)進(jìn)行淘汰。
timeBetweenEvictionRunsMillis參數(shù)就是設(shè)置掃描周期的,這也和上面的參數(shù)說明相對應(yīng)。

    /**
     * <p>Starts the evictor with the given delay. If there is an evictor
     * running when this method is called, it is stopped and replaced with a
     * new evictor with the specified delay.</p>
     *
     * <p>This method needs to be final, since it is called from a constructor.
     * See POOL-195.</p>
     *
     * @param delay time in milliseconds before start and between eviction runs
     *
     * 進(jìn)行同步控制保證evictor為單例
     */
    final void startEvictor(final long delay) {
        synchronized (evictionLock) {
            if (null != evictor) {
                EvictionTimer.cancel(evictor, evictorShutdownTimeoutMillis, TimeUnit.MILLISECONDS);
                evictor = null;
                evictionIterator = null;
            }
            if (delay > 0) {
                evictor = new Evictor();
                //開啟淘汰任務(wù)
                EvictionTimer.schedule(evictor, delay, delay);
            }
        }
    }

這里主要做Evictor的創(chuàng)建,EvictionTimer是一個(gè)基于ScheduledThreadPoolExecutor進(jìn)行線程調(diào)度的。

    /**
     * The idle object evictor {@link TimerTask}.
     * 空閑對象的淘汰任務(wù)
     * @see GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis
     */
    class Evictor extends TimerTask {
        /**
         * Run pool maintenance.  Evict objects qualifying for eviction and then
         * ensure that the minimum number of idle instances are available.
         * Since the Timer that invokes Evictors is shared for all Pools but
         * pools may exist in different class loaders, the Evictor ensures that
         * any actions taken are under the class loader of the factory
         * associated with the pool.
         */
        @Override
        public void run() {
            //創(chuàng)建class Loader 來保證對象是在一個(gè)ClassLoader中
            final ClassLoader savedClassLoader =
                    Thread.currentThread().getContextClassLoader();
            try {
                if (factoryClassLoader != null) {
                    // Set the class loader for the factory
                    final ClassLoader cl = factoryClassLoader.get();
                    if (cl == null) {
                        // The pool has been dereferenced and the class loader
                        // GC'd. Cancel this timer so the pool can be GC'd as
                        // well.
                        cancel();
                        return;
                    }
                    Thread.currentThread().setContextClassLoader(cl);
                }

                // Evict from the pool
                try {
                    //進(jìn)行淘汰
                    evict();
                } catch(final Exception e) {
                    swallowException(e);
                } catch(final OutOfMemoryError oome) {
                    // Log problem but give evictor thread a chance to continue
                    // in case error is recoverable
                    oome.printStackTrace(System.err);
                }
                // Re-create idle instances.
                try {
                    ensureMinIdle();
                } catch (final Exception e) {
                    swallowException(e);
                }
            } finally {
                // Restore the previous CCL
                Thread.currentThread().setContextClassLoader(savedClassLoader);
            }
        }
    }

這里調(diào)用了evict();方法,這個(gè)方法的實(shí)現(xiàn)是在子類中的:

    /**
     * {@inheritDoc}
     * <p>
     * Successive activations of this method examine objects in sequence,
     * cycling through objects in oldest-to-youngest order.
     *
     * 進(jìn)行空閑連接的淘汰
     */
    @Override
    public void evict() throws Exception {
        assertOpen();
        //判斷空閑的線程池是否為空,為空那么不進(jìn)行淘汰
        if (idleObjects.size() > 0) {
            PooledObject<T> underTest = null;
            //獲取淘汰策略,默認(rèn)是DefaultEvictionPolicy
            final EvictionPolicy<T> evictionPolicy = getEvictionPolicy();

            synchronized (evictionLock) {
                //淘汰的配置設(shè)置
                final EvictionConfig evictionConfig = new EvictionConfig(
                        getMinEvictableIdleTimeMillis(),//最小的空閑時(shí)間
                        getSoftMinEvictableIdleTimeMillis(),
                        getMinIdle());//最小的空閑數(shù)
                //是否對空閑的連接進(jìn)行Test
                final boolean testWhileIdle = getTestWhileIdle();
                //getNumTests為一次淘汰策略的運(yùn)行掃描多少對象
                for (int i = 0, m = getNumTests(); i < m; i++) {
                    //是否要?jiǎng)?chuàng)建淘汰的迭代器
                    if (evictionIterator == null || !evictionIterator.hasNext()) {
                        evictionIterator = new EvictionIterator(idleObjects);
                    }
                    //如果當(dāng)前的迭代器是空的,那么證明當(dāng)前的空閑對象池已經(jīng)用光了,那么不進(jìn)行淘汰
                    if (!evictionIterator.hasNext()) {
                        // Pool exhausted, nothing to do here
                        return;
                    }

                    try {
                        underTest = evictionIterator.next();
                    } catch (final NoSuchElementException nsee) {
                        // Object was borrowed in another thread
                        // Don't count this as an eviction test so reduce i;
                        i--;
                        evictionIterator = null;
                        continue;
                    }
                    //將當(dāng)前的空閑的連接設(shè)置為淘汰狀態(tài),不為空閑則重新迭代出一個(gè)
                    if (!underTest.startEvictionTest()) {
                        // Object was borrowed in another thread
                        // Don't count this as an eviction test so reduce i;
                        i--;
                        continue;
                    }

                    // User provided eviction policy could throw all sorts of
                    // crazy exceptions. Protect against such an exception
                    // killing the eviction thread.
                    boolean evict;
                    try {
                        //根據(jù)淘汰策略判斷是否需要淘汰
                        evict = evictionPolicy.evict(evictionConfig, underTest,
                                idleObjects.size());
                    } catch (final Throwable t) {
                        // Slightly convoluted as SwallowedExceptionListener
                        // uses Exception rather than Throwable
                        PoolUtils.checkRethrow(t);
                        swallowException(new Exception(t));
                        // Don't evict on error conditions
                        evict = false;
                    }
                    //如果需要淘汰,那么執(zhí)行淘汰邏輯
                    if (evict) {
                        destroy(underTest);
                        destroyedByEvictorCount.incrementAndGet();
                    } else {//如果不需要淘汰,判斷是否進(jìn)行對象有效期的校驗(yàn)
                        if (testWhileIdle) {
                            boolean active = false;
                            try {
                                //對對象進(jìn)行激活
                                factory.activateObject(underTest);
                                active = true;
                            } catch (final Exception e) {
                                destroy(underTest);
                                destroyedByEvictorCount.incrementAndGet();
                            }
                            if (active) {
                                //對對象的有效性進(jìn)行檢測
                                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)) {
                            // TODO - May need to add code here once additional
                            // states are used
                        }
                    }
                }
            }
        }
        final AbandonedConfig ac = this.abandonedConfig;
        if (ac != null && ac.getRemoveAbandonedOnMaintenance()) {
            removeAbandoned(ac);
        }
    }

這里邏輯比較長,做了下面幾件事:

  1. 判斷空閑對象池大小,大于0才允許淘汰。
  2. 接下來獲取一系列的配置,其中testWhileIdle主要用于判斷是否進(jìn)行空閑檢查。
  3. 根據(jù)numTestsPerEvictionRun確定一次淘汰要檢查的空閑對象的數(shù)目。
  4. 創(chuàng)建evictionIterator迭代器,迭代出一個(gè)待檢查的對象,并判斷對象的狀態(tài),如果狀態(tài)不為空閑狀態(tài),那么返回重新選一個(gè)空閑的對象。如果是空閑狀態(tài)那么設(shè)置為EVICTION。
  5. 獲取淘汰機(jī)制,默認(rèn)是DefaultEvictionPolicy:
public class DefaultEvictionPolicy<T> implements EvictionPolicy<T> {

    @Override
    public boolean evict(final EvictionConfig config, final PooledObject<T> underTest,
            final int idleCount) {
        //首先獲取
        if ((config.getIdleSoftEvictTime() < underTest.getIdleTimeMillis() &&
                config.getMinIdle() < idleCount) ||
                config.getIdleEvictTime() < underTest.getIdleTimeMillis()) {
            return true;
        }
        return false;
    }
}

這里主要涉及到之前的幾個(gè)配置:
MinEvictableIdleTimeMillis,SoftMinEvictableIdleTimeMillis和MinIdle
根據(jù)上面代碼我們可知:
當(dāng)對象的空閑時(shí)間大于SoftMinEvictableIdleTimeMillis并且空閑對象數(shù)小于實(shí)際的空閑線程時(shí),會進(jìn)行淘汰。或者空閑時(shí)間大于IdleEvictTime時(shí)會淘汰,也就是說上面的情況會保證當(dāng)前最小對象數(shù),也就是所描述的“soft”

  1. 如果需要淘汰,那么執(zhí)行destroy方法進(jìn)行對象淘汰。如果不需要淘汰,并且設(shè)置了空閑檢查,那么進(jìn)行一系列的檢查操作,首先進(jìn)行activateObject來激活對象,接著利用validateObject判斷對象的有效性,最后鈍化對象passivateObject。
  2. 將檢查對象狀態(tài)設(shè)置為空閑。
    這就是整個(gè)空閑淘汰的過程。

相比較于核心功能——對象緩存,空閑淘汰還是閑的可有可無,畢竟不是核心功能。接下來看下對象的獲取的實(shí)現(xiàn):
如果想從對象池中獲取一個(gè)對象,需要調(diào)用borrowObject方法:

    /**
     * Equivalent to <code>{@link #borrowObject(long)
     * borrowObject}({@link #getMaxWaitMillis()})</code>.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public T borrowObject() throws Exception {
        return borrowObject(getMaxWaitMillis());
    }

這里可以看到用到了一個(gè)參數(shù)maxWaitMillis,這個(gè)參數(shù)主要是設(shè)置如果獲取不到對象最大需要等待的時(shí)間。核心實(shí)現(xiàn)在borrowObject(getMaxWaitMillis())里:

    public T borrowObject(final long borrowMaxWaitMillis) throws Exception {
        assertOpen();

        final AbandonedConfig ac = this.abandonedConfig;
        if (ac != null && ac.getRemoveAbandonedOnBorrow() &&
                (getNumIdle() < 2) &&
                (getNumActive() > getMaxTotal() - 3) ) {
            removeAbandoned(ac);
        }

        PooledObject<T> p = null;

        // Get local copy of current config so it is consistent for entire
        // method execution
        //當(dāng)資源池耗盡的時(shí)候是否阻塞住
        final boolean blockWhenExhausted = getBlockWhenExhausted();

        boolean create;
        final long waitTime = System.currentTimeMillis();

        while (p == null) {
            create = false;
            p = idleObjects.pollFirst();//彈出一個(gè)對象
            if (p == null) {//如果為空,那么新創(chuàng)建,這里也可能創(chuàng)建成功,也可能創(chuàng)建失敗
                p = create();
                if (p != null) {
                    create = true;
                }
            }
            //如果空閑對象耗盡的情況下是否阻塞等待
            if (blockWhenExhausted) {
                if (p == null) {
                    //沒有設(shè)置超時(shí)時(shí)間的話,那么利用take阻塞到有資源為止
                    if (borrowMaxWaitMillis < 0) {
                        p = idleObjects.takeFirst();
                    } else {
                        //等待borrowMaxWaitMillis
                        p = idleObjects.pollFirst(borrowMaxWaitMillis,
                                TimeUnit.MILLISECONDS);
                    }
                }
                if (p == null) {
                    //超時(shí)未獲取,拋出獲取不到的異常
                    throw new NoSuchElementException(
                            "Timeout waiting for idle object");
                }
            } else {
                //如果耗盡的時(shí)候不阻塞等待,那么直接拋出異常
                if (p == null) {
                    throw new NoSuchElementException("Pool exhausted");
                }
            }
            //判斷當(dāng)前的對象的狀態(tài)是否為idle
            if (!p.allocate()) {
                p = null;
            }
            //如果獲取到對象,那么進(jìn)行對象的一系列的校驗(yàn)等操作
            if (p != null) {
                try {
                    //激活對象
                    factory.activateObject(p);
                } catch (final Exception e) {
                    //異常則執(zhí)行銷毀操作
                    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;
                    }
                }
                //這里主要是獲取testOnBorrow和testOnCreate,那么在對象是從idle池中取出來的或者是新創(chuàng)建的要進(jìn)行Test
                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;
                    }
                    //如果無效的話進(jìn)行銷毀操作
                    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;
                        }
                    }
                }
            }
        }
        //更新一些統(tǒng)計(jì)信息
        updateStatsBorrow(p, System.currentTimeMillis() - waitTime);

        return p.getObject();
    }

整個(gè)流程和ThreadPoolExecutor獲取任務(wù)差不多,但是中間還摻雜了創(chuàng)建新的對象的邏輯,這里有幾個(gè)參數(shù):
borrowMaxWaitMillis:對象池空閑時(shí)最大的等待時(shí)間。
blockWhenExhausted:在對象池耗盡的時(shí)候是否要進(jìn)行等待。
testOnBorrow:borrow對象的時(shí)候是否要檢測。
testOnCreate:新創(chuàng)建對象的時(shí)候是否要進(jìn)行檢測。

大體流程我們看明白了,但是總感覺少點(diǎn)什么。對象什么時(shí)候創(chuàng)建?活躍的對象是怎么表示的?

首先,對象采用懶加載的形式進(jìn)行創(chuàng)建,在調(diào)用create()方法時(shí)進(jìn)行創(chuàng)建:

    /**
     * Attempts to create a new wrapped pooled object.
     * <p>
     * If there are {@link #getMaxTotal()} objects already in circulation
     * or in process of being created, this method returns null.
     *
     * @return The new wrapped pooled object
     *
     * @throws Exception if the object factory's {@code makeObject} fails
     */
    private PooledObject<T> create() throws Exception {
        //獲取最大的對象數(shù)
        int localMaxTotal = getMaxTotal();
        // This simplifies the code later in this method
        if (localMaxTotal < 0) {
            localMaxTotal = Integer.MAX_VALUE;
        }

        // Flag that indicates if create should:
        // - TRUE:  call the factory to create an object
        // - FALSE: return null
        // - null:  loop and re-test the condition that determines whether to
        //          call the factory
        Boolean create = null;
        //這里采用while去做創(chuàng)建和JDK的線程池實(shí)現(xiàn)類似
        while (create == null) {
            synchronized (makeObjectCountLock) {
                //增加創(chuàng)建數(shù)
                final long newCreateCount = createCount.incrementAndGet();
                //和最大的對象數(shù)想比較
                if (newCreateCount > localMaxTotal) {
                    //如果超限,回滾下
                    // The pool is currently at capacity or in the process of
                    // making enough new objects to take it to capacity.
                    //減小創(chuàng)建數(shù)
                    createCount.decrementAndGet();
                    //正在創(chuàng)建的Object數(shù)目,正在創(chuàng)建的為0,那么也就不用等待了
                    if (makeObjectCount == 0) {
                        // There are no makeObject() calls in progress so the
                        // pool is at capacity. Do not attempt to create a new
                        // object. Return and wait for an object to be returned
                        create = Boolean.FALSE;
                    } else {
                        //如果正在創(chuàng)建的對象數(shù)不為0,意味著目前可能對象池還沒有用超限,并且有失敗的,那么進(jìn)行重試
                        // There are makeObject() calls in progress that might
                        // bring the pool to capacity. Those calls might also
                        // fail so wait until they complete and then re-test if
                        // the pool is at capacity or not.
                        makeObjectCountLock.wait();
                    }
                } else {
                    //創(chuàng)建新對象
                    // The pool is not at capacity. Create a new object.
                    makeObjectCount++;
                    create = Boolean.TRUE;
                }
            }
        }
        //如果沒有新的對象創(chuàng)建,那么返回
        if (!create.booleanValue()) {
            return null;
        }

        //創(chuàng)建新對象
        final PooledObject<T> p;
        try {
            p = factory.makeObject();
        } catch (Exception e) {
            createCount.decrementAndGet();
            throw e;
        } finally {
            //釋放鎖,并且喚醒其他的等待線程,表明當(dāng)前已經(jīng)有線程創(chuàng)建好了對象了
            synchronized (makeObjectCountLock) {
                makeObjectCount--;
                makeObjectCountLock.notifyAll();
            }
        }

        final AbandonedConfig ac = this.abandonedConfig;
        if (ac != null && ac.getLogAbandoned()) {
            p.setLogAbandoned(true);
        }
        //增加創(chuàng)建的數(shù)量
        createdCount.incrementAndGet();
        //將新創(chuàng)建的對象添加到Map中
        allObjects.put(new IdentityWrapper<T>(p.getObject()), p);
        return p;
    }

新對象創(chuàng)建這里比較有意思,首先要判斷當(dāng)前的對象數(shù)有沒有超過對象總量的限制,如果超限了,那么就不能創(chuàng)建新對象了,然后通過makeObjectCount判斷有沒有正在創(chuàng)建對象的線程在創(chuàng)建對象,makeObjectCount只是一個(gè)long類型,這里主要通過makeObjectCountLock來保證可見性,如果當(dāng)前有線程在創(chuàng)建對象那么wait()一下,因?yàn)檫@里存在創(chuàng)建失敗的問題,如果之前的創(chuàng)建失敗,可能會導(dǎo)致newCreateCount短暫的超過最大上限。通過makeObject創(chuàng)建新對象。創(chuàng)建之后喚醒等待的線程。
這里出現(xiàn)了一個(gè)allObjects,它是ConcurrentHashMap,新創(chuàng)建的對象不直接加入到idle隊(duì)列中,而是加入到ConcurrentHashMap中,只有在對象return的時(shí)候才返回到idle隊(duì)列中。新創(chuàng)建的對象被標(biāo)示為ALLOCATED狀態(tài)。并且緩存在ConcurrentHashMap中。

    /**
     * Allocates the object.
     *
     * @return {@code true} if the original state was {@link PooledObjectState#IDLE IDLE}
     */
    @Override
    public synchronized boolean allocate() {
        if (state == PooledObjectState.IDLE) {
            state = PooledObjectState.ALLOCATED;
            lastBorrowTime = System.currentTimeMillis();
            lastUseTime = lastBorrowTime;
            borrowedCount++;
            if (logAbandoned) {
                borrowedBy = new AbandonedObjectCreatedException();
            }
            return true;
        } else if (state == PooledObjectState.EVICTION) {
            // TODO Allocate anyway and ignore eviction test
            state = PooledObjectState.EVICTION_RETURN_TO_HEAD;
            return false;
        }
        // TODO if validating and testOnBorrow == true then pre-allocate for
        // performance
        return false;
    }

這樣borrowObject的流程就結(jié)束了,這里主要比較重要的就是,新創(chuàng)建的對象是緩存在ConcurrentHashMap中的而不是idle隊(duì)列。

接下來看下returnObject,將整體的流程走通:

    /**
     * {@inheritDoc}
     * <p>
     * If {@link #getMaxIdle() maxIdle} is set to a positive value and the
     * number of idle instances has reached this value, the returning instance
     * is destroyed.
     * <p>
     * If {@link #getTestOnReturn() testOnReturn} == true, the returning
     * instance is validated before being returned to the idle instance pool. In
     * this case, if validation fails, the instance is destroyed.
     * <p>
     * Exceptions encountered destroying objects for any reason are swallowed
     * but notified via a {@link SwallowedExceptionListener}.
     */
    @Override
    public void returnObject(final T obj) {
        //從ConcurrentHashMap中獲取相應(yīng)的PooledObject
        final PooledObject<T> p = allObjects.get(new IdentityWrapper<T>(obj));

        if (p == null) {
            if (!isAbandonedConfig()) {
                throw new IllegalStateException(
                        "Returned object not currently part of this pool");
            }
            return; // Object was abandoned and removed
        }

        synchronized(p) {
            final PooledObjectState state = p.getState();
            //確定返回的對象都是ALLOCATED狀態(tài)的
            if (state != PooledObjectState.ALLOCATED) {
                throw new IllegalStateException(
                        "Object has already been returned to this pool or is invalid");
            }
            //將狀態(tài)設(shè)置為RETURNING
            p.markReturning(); // Keep from being marked abandoned
        }

        final long activeTime = p.getActiveTimeMillis();
        //判斷在對象返回的時(shí)候是否需要Test
        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;
        }
        //將對象狀態(tài)設(shè)置為IDLE
        if (!p.deallocate()) {
            throw new IllegalStateException(
                    "Object has already been returned to this pool or is invalid");
        }
        //獲取最大的空閑的對象池大小
        final int maxIdleSave = getMaxIdle();
        //如果對象池Close,或者超限了,那么直接銷毀對象
        if (isClosed() || maxIdleSave > -1 && maxIdleSave <= idleObjects.size()) {
            try {
                destroy(p);
            } catch (final Exception e) {
                swallowException(e);
            }
        } else {
            //進(jìn)行空閑對象入隊(duì),這里主要是判斷是否是FIFO的模式
            if (getLifo()) {
                idleObjects.addFirst(p);
            } else {
                idleObjects.addLast(p);
            }
            //如果close了,那么清理所有對象
            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);
    }

這里比較關(guān)鍵的點(diǎn)是,對象的返還,是先到ConcurrentHashMap中找到對象,并且標(biāo)示它的狀態(tài),最后轉(zhuǎn)換為IDLE,最后返還給IDLE隊(duì)列中。也就是說ConcurrentHashMap維護(hù)了所有的對象,而IDLE隊(duì)列只是維護(hù)空閑的對象。
這樣整個(gè)Commons-pool主干流程就分析完了,這里其實(shí)效果不是太好,最好是結(jié)合JedisPool和DBCP來看,同時(shí)也有一些邊角的東西不能完全看到,如果有遺漏的東西,還請指出。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,506評論 19 139
  • 前言 Apache-Commons-DBCP是數(shù)據(jù)庫連接池中一款優(yōu)秀的產(chǎn)品,熟悉dbcp同學(xué)都知道,dbcp底層“...
    許da廣閱讀 2,773評論 1 6
  • 這些屬性是否生效取決于對應(yīng)的組件是否聲明為 Spring 應(yīng)用程序上下文里的 Bean(基本是自動配置的),為一個(gè)...
    發(fā)光的魚閱讀 1,482評論 0 14
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,253評論 6 342
  • application的配置屬性。 這些屬性是否生效取決于對應(yīng)的組件是否聲明為Spring應(yīng)用程序上下文里的Bea...
    新簽名閱讀 5,530評論 1 27

友情鏈接更多精彩內(nèi)容