jedis鏈接池參數minEvictableIdleTimeMillis和softMinEvictableIdleTimeMillis探索

咱們一般在使用JedisPoolConfig進行鏈接池配置的時候,minEvictableIdleTimeMillis和softMinEvictableIdleTimeMillis這兩個參數常常會不懂其含義,
查各類資料也沒有很是明確的說到底該如何設置,即便知道如何設置,也不知道其原理,只知道這兩個參數是和逐出線程有關的。下面根據源碼進行探索。
咱們一般是經過JedisPool構造線程池,追溯其父類的建立過程,發現Pool<T>這個泛型類的構造方法調用過程以下:java

public Pool(GenericObjectPoolConfig poolConfig, PooledObjectFactory<T> factory) { this.initPool(poolConfig, factory); } public void initPool(GenericObjectPoolConfig poolConfig, PooledObjectFactory<T> factory) { if(this.internalPool != null) { try { this.closeInternalPool(); } catch (Exception var4) { ; } } this.internalPool = new GenericObjectPool(factory, poolConfig); }

發現其建立了一個GenericObjectPool對象,構造方法以下:apache

public GenericObjectPool(PooledObjectFactory<T> factory, GenericObjectPoolConfig config) { super(config, "org.apache.commons.pool2:type=GenericObjectPool,name=", config.getJmxNamePrefix()); this.factoryType = null; this.maxIdle = 8; this.minIdle = 0; this.allObjects = new ConcurrentHashMap(); this.createCount = new AtomicLong(0L); this.abandonedConfig = null; if(factory == null) { this.jmxUnregister(); throw new IllegalArgumentException("factory may not be null"); } else { this.factory = factory; this.idleObjects = new LinkedBlockingDeque(config.getFairness()); this.setConfig(config); this.startEvictor(this.getTimeBetweenEvictionRunsMillis()); } } 

其中this.startEvictor(this.getTimeBetweenEvictionRunsMillis());方法的調用,正是開啓逐出線程運行的做用,this

咱們能夠發現,源碼經過週期性的調度逐出任務(timeBetweenEvictionRunsMillis大於0時),將空閒的鏈接逐出線程池。spa

final void startEvictor(long delay) { Object var3 = this.evictionLock; synchronized(this.evictionLock) { if(null != this.evictor) { EvictionTimer.cancel(this.evictor); this.evictor = null; this.evictionIterator = null; } if(delay > 0L) { this.evictor = new BaseGenericObjectPool.Evictor(); EvictionTimer.schedule(this.evictor, delay, delay); } } } 

下面將是咱們今天研究的重點,this.evictor。線程

逐出有逐出策略,若是不配置則採用默認的逐出策略DefaultEvictionPolicy,其中的evict方法返回true時才執行逐出的操做code

public class DefaultEvictionPolicy<T> implements EvictionPolicy<T> { public DefaultEvictionPolicy() { } public boolean evict(EvictionConfig config, PooledObject<T> underTest, int idleCount) { return config.getIdleSoftEvictTime() < underTest.getIdleTimeMillis() && config.getMinIdle() < idleCount || config.getIdleEvictTime() < underTest.getIdleTimeMillis(); } }

真正的逐出方法執行的是如下內容對象

public void evict() throws Exception { this.assertOpen(); if(this.idleObjects.size() > 0) { PooledObject<T> underTest = null; EvictionPolicy<T> evictionPolicy = this.getEvictionPolicy(); Object var3 = this.evictionLock; synchronized(this.evictionLock) { EvictionConfig evictionConfig = new EvictionConfig(this.getMinEvictableIdleTimeMillis(), this.getSoftMinEvictableIdleTimeMillis(), this.getMinIdle()); boolean testWhileIdle = this.getTestWhileIdle(); int i = 0; int m = this.getNumTests(); while(true) { if(i >= m) { break; } if(this.evictionIterator == null || !this.evictionIterator.hasNext()) { this.evictionIterator = new EvictionIterator(this, this.idleObjects); } if(!this.evictionIterator.hasNext()) { return; } label81: { try { underTest = this.evictionIterator.next(); } catch (NoSuchElementException var15) { --i; this.evictionIterator = null; break label81; } if(!underTest.startEvictionTest()) { --i; } else { boolean evict; try { evict = evictionPolicy.evict(evictionConfig, underTest, this.idleObjects.size()); } catch (Throwable var14) { PoolUtils.checkRethrow(var14); this.swallowException(new Exception(var14)); evict = false; } if(evict) { this.destroy(underTest); this.destroyedByEvictorCount.incrementAndGet(); } else { if(testWhileIdle) { boolean active = false; try { this.factory.activateObject(underTest); active = true; } catch (Exception var13) { this.destroy(underTest); this.destroyedByEvictorCount.incrementAndGet(); } if(active) { if(!this.factory.validateObject(underTest)) { this.destroy(underTest); this.destroyedByEvictorCount.incrementAndGet(); } else { try { this.factory.passivateObject(underTest); } catch (Exception var12) { this.destroy(underTest); this.destroyedByEvictorCount.incrementAndGet(); } } } } if(!underTest.endEvictionTest(this.idleObjects)) { ; } } } } ++i; } } } AbandonedConfig ac = this.abandonedConfig; if(ac != null && ac.getRemoveAbandonedOnMaintenance()) { this.removeAbandoned(ac); } } 

咱們重點看兩行代碼,第8行是建立了逐出配置,根據你配置的minEvictableIdleTimeMillis和softMinEvictableIdleTimeMillis,若是存在負數,則設爲long類型的最大值。blog

public EvictionConfig(long poolIdleEvictTime, long poolIdleSoftEvictTime, int minIdle) { if(poolIdleEvictTime > 0L) { this.idleEvictTime = poolIdleEvictTime; } else { this.idleEvictTime = 9223372036854775807L; } if(poolIdleSoftEvictTime > 0L) { this.idleSoftEvictTime = poolIdleSoftEvictTime; } else { this.idleSoftEvictTime = 9223372036854775807L; } this.minIdle = minIdle; } 

再看第40行代碼,再結合DefaultEvictionPolicy的evict方法,咱們能夠看到,真正的逐出依據是:進程

1.鏈接空閒時間大於softMinEvictableIdleTimeMillis而且當前鏈接池的空閒鏈接數大於最小空閒鏈接數minIdle;rem

2.鏈接空閒時間大於minEvictableIdleTimeMillis。

1或者2成當即可逐出,注意是或的關係。

因此,結論以下:

若是要鏈接池只根據softMinEvictableIdleTimeMillis進程逐出,那麼須要將minEvictableIdleTimeMillis設置爲負數(即最大值);
若是要鏈接池只根據minEvictableIdleTimeMillis進程逐出,那麼須要將softMinEvictableIdleTimeMillis設置爲負數(即最大值),理論上設置minIdle很大也是能夠的,可是實際上不行;

相關文章
相關標籤/搜索