之前學(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):

主要關(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類圖如下:

其中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);
}
}
這里邏輯比較長,做了下面幾件事:
- 判斷空閑對象池大小,大于0才允許淘汰。
- 接下來獲取一系列的配置,其中testWhileIdle主要用于判斷是否進(jìn)行空閑檢查。
- 根據(jù)numTestsPerEvictionRun確定一次淘汰要檢查的空閑對象的數(shù)目。
- 創(chuàng)建evictionIterator迭代器,迭代出一個(gè)待檢查的對象,并判斷對象的狀態(tài),如果狀態(tài)不為空閑狀態(tài),那么返回重新選一個(gè)空閑的對象。如果是空閑狀態(tài)那么設(shè)置為EVICTION。
- 獲取淘汰機(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”
- 如果需要淘汰,那么執(zhí)行destroy方法進(jìn)行對象淘汰。如果不需要淘汰,并且設(shè)置了空閑檢查,那么進(jìn)行一系列的檢查操作,首先進(jìn)行activateObject來激活對象,接著利用validateObject判斷對象的有效性,最后鈍化對象passivateObject。
- 將檢查對象狀態(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í)也有一些邊角的東西不能完全看到,如果有遺漏的東西,還請指出。