續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