commons-pool2源碼分析evictor

http://my.oschina.net/chengxiaoyuan/blog/607582 ,commons-pool2中有個驅逐機制Evictor定時任務,看其實怎麼啓動的 :java


在初始化對象池GenericObjectPool的時候對調用父類的startEvictor方法,父類初始化一個TimerTask的子類Evictor交由Timer定時執行,Evictor中的run方法最終仍是調用當前對象池的evict方法和ensureMinIdle方法,下面看具體的代碼分析:ide

GenericObjectPool
測試

    public GenericObjectPool(PooledObjectFactory<T> factory,
            GenericObjectPoolConfig config) {
        ...//省略
        startEvictor(getTimeBetweenEvictionRunsMillis());//配置timeBetweenEvictionRunsMillis
    }

BaseGenericObjectPoolthis

    final void startEvictor(long delay) {
        synchronized (evictionLock) {
            if (null != evictor) {
                EvictionTimer.cancel(evictor);
                evictor = null;
                evictionIterator = null;
            }
            //timeBetweenEvictionRunsMillis>0纔會啓動
            if (delay > 0) {
                evictor = new Evictor();
                EvictionTimer.schedule(evictor, delay, delay);
            }
        }
    }

BaseGenericObjectPool的內部類Evictor.net

    /**
     * The idle object evictor {@link TimerTask}.
     *
     * @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() {
            ClassLoader savedClassLoader =
                    Thread.currentThread().getContextClassLoader();
            try {
                if (factoryClassLoader != null) {
                    // Set the class loader for the factory
                    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 {
                    evict();//具體的驅逐方法, 由具體子類實現
                } catch(Exception e) {
                    swallowException(e);
                } catch(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 (Exception e) {
                    swallowException(e);
                }
            } finally {
                // Restore the previous CCL
                Thread.currentThread().setContextClassLoader(savedClassLoader);
            }
        }
    }

以GenericObjectPool爲例看evict()和ensureMinIdle()code

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

        if (idleObjects.size() > 0) {//若是空閒數大於0

            PooledObject<T> underTest = null;
            EvictionPolicy<T> evictionPolicy = getEvictionPolicy();//evict的策略

            synchronized (evictionLock) {
                EvictionConfig evictionConfig = new EvictionConfig(
                        getMinEvictableIdleTimeMillis(),
                        getSoftMinEvictableIdleTimeMillis(),
                        getMinIdle());//驅逐配置,後面驅逐策略須要用到

                boolean testWhileIdle = getTestWhileIdle();//空閒時檢查開關

                //getNumTests爲每次檢查對象數量
                for (int i = 0, m = getNumTests(); i < m; i++) {
                    if (evictionIterator == null || !evictionIterator.hasNext()) {
                        evictionIterator = new EvictionIterator(idleObjects);
                    }
                    if (!evictionIterator.hasNext()) {
                        // Pool exhausted, nothing to do here
                        return;
                    }

                    try {
                        underTest = evictionIterator.next();
                    } catch (NoSuchElementException nsee) {
                        // Object was borrowed in another thread
                        // Don't count this as an eviction test so reduce i;
                        i--;
                        evictionIterator = null;
                        continue;
                    }

                    //修改狀態
                    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 {
                        //根據策略進行判斷是否須要驅逐,默認策略DefaultEvictionPolicy
                        evict = evictionPolicy.evict(evictionConfig, underTest,
                                idleObjects.size());
                    } catch (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;
                    }

                    if (evict) {//須要驅逐的對象直接銷燬
                        destroy(underTest);
                        destroyedByEvictorCount.incrementAndGet();
                    } else {
                        if (testWhileIdle) {//若是空閒時檢查
                            boolean active = false;
                            try {
                                factory.activateObject(underTest);//激活
                                active = true;
                            } catch (Exception e) {
                                destroy(underTest);//激活失敗就銷燬
                                destroyedByEvictorCount.incrementAndGet();
                            }
                            if (active) {
                                if (!factory.validateObject(underTest)) {//驗證
                                    destroy(underTest);//驗證失敗就銷燬
                                    destroyedByEvictorCount.incrementAndGet();
                                } else {
                                    try {
                                        factory.passivateObject(underTest);//驗證成功就鈍化
                                    } catch (Exception e) {
                                        destroy(underTest);
                                        destroyedByEvictorCount.incrementAndGet();
                                    }
                                }
                            }
                        }
                        //驅逐測試結束,修改狀態
                        if (!underTest.endEvictionTest(idleObjects)) {
                            // TODO - May need to add code here once additional
                            // states are used
                        }
                    }
                }
            }
        }
        //移除廢棄對象
        AbandonedConfig ac = this.abandonedConfig;
        if (ac != null && ac.getRemoveAbandonedOnMaintenance()) {
            removeAbandoned(ac);
        }
    }

    private void ensureIdle(int idleCount, boolean always) throws Exception {
        if (idleCount < 1 || isClosed() || (!always && !idleObjects.hasTakeWaiters())) {
            return;
        }

        //若是空閒數小於最小閥值就一直建立對象
        while (idleObjects.size() < idleCount) {
            PooledObject<T> 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()) {
            // 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();
        }
    }

DefaultEvictionPolicy對象

public class DefaultEvictionPolicy<T> implements EvictionPolicy<T> {

    @Override
    public boolean evict(EvictionConfig config, PooledObject<T> underTest,
            int idleCount) {

        //1.若是對象空閒時間大於IdleSoftEvictTime而且空閒數量大於最小空閒閥值
        //2.若是對象空閒時間大於IdleEvictTime
        //知足上面的一種狀況就返回true
        if ((config.getIdleSoftEvictTime() < underTest.getIdleTimeMillis() &&
                config.getMinIdle() < idleCount) ||
                config.getIdleEvictTime() < underTest.getIdleTimeMillis()) {
            return true;
        }
        return false;
    }
}
//IdleEvictTime比IdleSoftEvictTime要嚴格一點,因此正常配置IdleEvictTime>IdleSoftEvictTime
這兩個配置在BaseObjectPoolConfig中的體現:
//IdleEvictTime對應配置爲:minEvictableIdleTimeMillis
//IdleSoftEvictTime對應配置爲softMinEvictableIdleTimeMillis
相關文章
相關標籤/搜索