之前学习了一下Jedis的操作原理和JedisPool的相关实现,但是在JedisPool的实现中对于JedisPool的连接池实现没有深入的学习,因为JedisPool的连接池的实现是基于Apache Commons-pool的,所以只要重点关注Apache Commons-pool就OK了,之前在看Mybatis的连接池的实现时候有关注DBCP的连接池的实现,DBCP的连接池就是靠Apache Commons-pool来支撑的,所以这里也算是把DBCP底层的连接池也学习了一下。
Apache Commons-pool是一个Apache组织开源的对象池。我们所熟知的基本上就是DBCP和JedisPool了。对于这种“池”的概念Apache Commons-pool做了很好的支撑,也能尽量的将使用方和对象池本身做一个很好的解耦。目前Apache Commons-pool托管在github上,地址是:
Apache Commons-pool整体的代码结构并不复杂,下面是代码结构:
主要关键的类都在pool2包下,impl里面是一些默认的实现,proxy是提供的一些代理的支持。
对于用过JedisPool的童鞋来说呢,对于一个类一定不陌生,那就是GenericObjectPoolConfig,最开始用的时候我也是被各种参数弄得晕头转向,归根结底还是对pool的概念的模糊。本文的目的就是弄懂原理,弄清楚各个参数都是干嘛用的。
首先看一些关键的参数和说明吧:
lifo:对象池存储空闲对象是使用的LinkedBlockingDeque,它本质上是一个支持FIFO和FILO的双向的队列,common-pool2中的LinkedBlockingDeque不是Java原生的队列,而有common-pool2重新写的一个双向队列。如果为true,表示使用FIFO获取对象。默认值是true.建议使用默认值。
fairness:common-pool2实现的LinkedBlockingDeque双向阻塞队列使用的是Lock锁。这个参数就是表示在实例化一个LinkedBlockingDeque时,是否使用lock的公平锁。默认值是false,建议使用默认值。
maxWaitMillis:当没有空闲连接时,获取一个对象的最大等待时间。如果这个值小于0,则永不超时,一直等待,直到有空闲对象到来。如果大于0,则等待maxWaitMillis长时间,如果没有空闲对象,将抛出NoSuchElementException异常。默认值是-1;可以根据需要自己调整,单位是毫秒。
minEvictableIdleTimeMillis:对象最小的空闲时间。如果为小于等于0,最Long的最大值,如果大于0,当空闲的时间大于这个值时,执行移除这个对象操作。默认值是1000L * 60L * 30L;即30分钟。这个参数是强制性的,只要空闲时间超过这个值,就会移除。
softMinEvictableIdleTimeMillis:对象最小的空间时间,如果小于等于0,取Long的最大值,如果大于0,当对象的空闲时间超过这个值,并且当前空闲对象的数量大于最小空闲数量(minIdle)时,执行移除操作。这个和上面的minEvictableIdleTimeMillis的区别是,它会保留最小的空闲对象数量。而上面的不会,是强制性移除的。默认值是-1;
numTestsPerEvictionRun:检测空闲对象线程每次检测的空闲对象的数量。默认值是3;如果这个值小于0,则每次检测的空闲对象数量等于当前空闲对象数量除以这个值的绝对值,并对结果向上取整。
testOnCreate:在创建对象时检测对象是否有效,true是,默认值是false。
testOnBorrow:在从对象池获取对象时是否检测对象有效,true是;默认值是false。
testOnReturn:在向对象池中归还对象时是否检测对象有效,true是,默认值是false。
testWhileIdle:在检测空闲对象线程检测到对象不需要移除时,是否检测对象的有效性。true是,默认值是false。
timeBetweenEvictionRunsMillis:空闲对象检测线程的执行周期,即多长时候执行一次空闲对象检测。单位是毫秒数。如果小于等于0,则不执行检测线程。默认值是-1;
blockWhenExhausted:当对象池没有空闲对象时,新的获取对象的请求是否阻塞。true阻塞。默认值是true;
maxTotal:对象池中管理的最多对象个数。默认值是8。
maxIdle:对象池中最大的空闲对象个数。默认值是8。
minIdle:对象池中最小的空闲对象个数。默认值是0。
其实光看参数,根本看不出它们都是做什么的,所以我们还是开始看代码,我们主要关注的类是GenericObjectPool,虽然Commons-pool提供了基于key的Object的缓存池,但是我们不常用:
GenericObjectPool的UML类图如下:
其中GenericObjectPool继承了BaseGenericObjectPool,实现了ObjectPool、GenericObjectPoolMXBean等接口,并且提供了泛型T来指定缓存对象的类型。
BaseGenericObjectPool中主要做了一些公共的实现,GenericObjectPool则是复写一些抽象方法,做具体的实现,GenericObjectPoolMXBean主要做一些JMX的监控。
/**
* 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用来给对象池创建对象
* @param factory The object factory to be used to create object instances
* used by this pool
*
* 对相应的对象池进行配置
* @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());
//参数设置
setConfig(config);
//开启淘汰机制,timeBetweenEvictionRunsMillis为淘汰的间隔
startEvictor(getTimeBetweenEvictionRunsMillis());
}
这里比较关键的就是PooledObjectFactory,PooledObjectFactory是外部使用对象池的使用者需要实现的关于待缓存的对象的创建、激活销毁等一系列操作的工厂。这也充分体现了“解耦”的思想,自己的东西自己管,很合理。
主要方法如下:
makeObject为创建对象的方法。
destroyObject为销毁对象的方法。
validateObject为校验对象有消息的方法。
activateObject为激活对象的方法。
passivateObject为钝化对象的方法。
其实就是在创建对象的时候利用Factoty的makeObject来创建,销毁的时候利用destroyObject来销毁.....
接下来呢创建了一个双端队列LinkedBlockingDeque作为idle队列缓存所有空闲的对象,显然是无界的,那么大小就需要外部去控制。这里有一个点就是BlockingDeque的锁竞争,默认是非公平的锁,这也是JDK默认选择的锁。吞吐量很重要哦。
fairness就是锁的类型。
接下来开启一个TimeTask对idle队列进行定时的扫描,必要时进行淘汰。
timeBetweenEvictionRunsMillis参数就是设置扫描周期的,这也和上面的参数说明相对应。
/**
* <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
*
* 进行同步控制保证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();
//开启淘汰任务
EvictionTimer.schedule(evictor, delay, delay);
}
}
}
这里主要做Evictor的创建,EvictionTimer是一个基于ScheduledThreadPoolExecutor进行线程调度的。
/**
* 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() {
//创建class Loader 来保证对象是在一个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 {
//进行淘汰
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);
}
}
}
这里调用了evict();方法,这个方法的实现是在子类中的:
/**
* {@inheritDoc}
* <p>
* Successive activations of this method examine objects in sequence,
* cycling through objects in oldest-to-youngest order.
*
* 进行空闲连接的淘汰
*/
@Override
public void evict() throws Exception {
assertOpen();
//判断空闲的线程池是否为空,为空那么不进行淘汰
if (idleObjects.size() > 0) {
PooledObject<T> underTest = null;
//获取淘汰策略,默认是DefaultEvictionPolicy
final EvictionPolicy<T> evictionPolicy = getEvictionPolicy();
synchronized (evictionLock) {
//淘汰的配置设置
final EvictionConfig evictionConfig = new EvictionConfig(
getMinEvictableIdleTimeMillis(),//最小的空闲时间
getSoftMinEvictableIdleTimeMillis(),
getMinIdle());//最小的空闲数
//是否对空闲的连接进行Test
final 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 (final 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 {
//根据淘汰策略判断是否需要淘汰
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;
}
//如果需要淘汰,那么执行淘汰逻辑
if (evict) {
destroy(underTest);
destroyedByEvictorCount.incrementAndGet();
} else {//如果不需要淘汰,判断是否进行对象有效期的校验
if (testWhileIdle) {
boolean active = false;
try {
//对对象进行激活
factory.activateObject(underTest);
active = true;
} catch (final Exception e) {
destroy(underTest);
destroyedByEvictorCount.incrementAndGet();
}
if (active) {
//对对象的有效性进行检测
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主要用于判断是否进行空闲检查。
- 根据numTestsPerEvictionRun确定一次淘汰要检查的空闲对象的数目。
- 创建evictionIterator迭代器,迭代出一个待检查的对象,并判断对象的状态,如果状态不为空闲状态,那么返回重新选一个空闲的对象。如果是空闲状态那么设置为EVICTION。
- 获取淘汰机制,默认是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;
}
}
这里主要涉及到之前的几个配置:
MinEvictableIdleTimeMillis,SoftMinEvictableIdleTimeMillis和MinIdle
根据上面代码我们可知:
当对象的空闲时间大于SoftMinEvictableIdleTimeMillis并且空闲对象数小于实际的空闲线程时,会进行淘汰。或者空闲时间大于IdleEvictTime时会淘汰,也就是说上面的情况会保证当前最小对象数,也就是所描述的“soft”
- 如果需要淘汰,那么执行destroy方法进行对象淘汰。如果不需要淘汰,并且设置了空闲检查,那么进行一系列的检查操作,首先进行activateObject来激活对象,接着利用validateObject判断对象的有效性,最后钝化对象passivateObject。
- 将检查对象状态设置为空闲。
这就是整个空闲淘汰的过程。
相比较于核心功能——对象缓存,空闲淘汰还是闲的可有可无,毕竟不是核心功能。接下来看下对象的获取的实现:
如果想从对象池中获取一个对象,需要调用borrowObject方法:
/**
* Equivalent to <code>{@link #borrowObject(long)
* borrowObject}({@link #getMaxWaitMillis()})</code>.
* <p>
* {@inheritDoc}
*/
@Override
public T borrowObject() throws Exception {
return borrowObject(getMaxWaitMillis());
}
这里可以看到用到了一个参数maxWaitMillis,这个参数主要是设置如果获取不到对象最大需要等待的时间。核心实现在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
//当资源池耗尽的时候是否阻塞住
final boolean blockWhenExhausted = getBlockWhenExhausted();
boolean create;
final long waitTime = System.currentTimeMillis();
while (p == null) {
create = false;
p = idleObjects.pollFirst();//弹出一个对象
if (p == null) {//如果为空,那么新创建,这里也可能创建成功,也可能创建失败
p = create();
if (p != null) {
create = true;
}
}
//如果空闲对象耗尽的情况下是否阻塞等待
if (blockWhenExhausted) {
if (p == null) {
//没有设置超时时间的话,那么利用take阻塞到有资源为止
if (borrowMaxWaitMillis < 0) {
p = idleObjects.takeFirst();
} else {
//等待borrowMaxWaitMillis
p = idleObjects.pollFirst(borrowMaxWaitMillis,
TimeUnit.MILLISECONDS);
}
}
if (p == null) {
//超时未获取,抛出获取不到的异常
throw new NoSuchElementException(
"Timeout waiting for idle object");
}
} else {
//如果耗尽的时候不阻塞等待,那么直接抛出异常
if (p == null) {
throw new NoSuchElementException("Pool exhausted");
}
}
//判断当前的对象的状态是否为idle
if (!p.allocate()) {
p = null;
}
//如果获取到对象,那么进行对象的一系列的校验等操作
if (p != null) {
try {
//激活对象
factory.activateObject(p);
} catch (final Exception e) {
//异常则执行销毁操作
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池中取出来的或者是新创建的要进行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;
}
//如果无效的话进行销毁操作
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;
}
}
}
}
}
//更新一些统计信息
updateStatsBorrow(p, System.currentTimeMillis() - waitTime);
return p.getObject();
}
整个流程和ThreadPoolExecutor获取任务差不多,但是中间还掺杂了创建新的对象的逻辑,这里有几个参数:
borrowMaxWaitMillis:对象池空闲时最大的等待时间。
blockWhenExhausted:在对象池耗尽的时候是否要进行等待。
testOnBorrow:borrow对象的时候是否要检测。
testOnCreate:新创建对象的时候是否要进行检测。
大体流程我们看明白了,但是总感觉少点什么。对象什么时候创建?活跃的对象是怎么表示的?
首先,对象采用懒加载的形式进行创建,在调用create()方法时进行创建:
/**
* 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 {
//获取最大的对象数
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去做创建和JDK的线程池实现类似
while (create == null) {
synchronized (makeObjectCountLock) {
//增加创建数
final long newCreateCount = createCount.incrementAndGet();
//和最大的对象数想比较
if (newCreateCount > localMaxTotal) {
//如果超限,回滚下
// The pool is currently at capacity or in the process of
// making enough new objects to take it to capacity.
//减小创建数
createCount.decrementAndGet();
//正在创建的Object数目,正在创建的为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 {
//如果正在创建的对象数不为0,意味着目前可能对象池还没有用超限,并且有失败的,那么进行重试
// 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 {
//创建新对象
// The pool is not at capacity. Create a new object.
makeObjectCount++;
create = Boolean.TRUE;
}
}
}
//如果没有新的对象创建,那么返回
if (!create.booleanValue()) {
return null;
}
//创建新对象
final PooledObject<T> p;
try {
p = factory.makeObject();
} catch (Exception e) {
createCount.decrementAndGet();
throw e;
} finally {
//释放锁,并且唤醒其他的等待线程,表明当前已经有线程创建好了对象了
synchronized (makeObjectCountLock) {
makeObjectCount--;
makeObjectCountLock.notifyAll();
}
}
final AbandonedConfig ac = this.abandonedConfig;
if (ac != null && ac.getLogAbandoned()) {
p.setLogAbandoned(true);
}
//增加创建的数量
createdCount.incrementAndGet();
//将新创建的对象添加到Map中
allObjects.put(new IdentityWrapper<T>(p.getObject()), p);
return p;
}
新对象创建这里比较有意思,首先要判断当前的对象数有没有超过对象总量的限制,如果超限了,那么就不能创建新对象了,然后通过makeObjectCount判断有没有正在创建对象的线程在创建对象,makeObjectCount只是一个long类型,这里主要通过makeObjectCountLock来保证可见性,如果当前有线程在创建对象那么wait()一下,因为这里存在创建失败的问题,如果之前的创建失败,可能会导致newCreateCount短暂的超过最大上限。通过makeObject创建新对象。创建之后唤醒等待的线程。
这里出现了一个allObjects,它是ConcurrentHashMap,新创建的对象不直接加入到idle队列中,而是加入到ConcurrentHashMap中,只有在对象return的时候才返回到idle队列中。新创建的对象被标示为ALLOCATED状态。并且缓存在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的流程就结束了,这里主要比较重要的就是,新创建的对象是缓存在ConcurrentHashMap中的而不是idle队列。
接下来看下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中获取相应的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状态的
if (state != PooledObjectState.ALLOCATED) {
throw new IllegalStateException(
"Object has already been returned to this pool or is invalid");
}
//将状态设置为RETURNING
p.markReturning(); // Keep from being marked abandoned
}
final long activeTime = p.getActiveTimeMillis();
//判断在对象返回的时候是否需要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;
}
//将对象状态设置为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 {
//进行空闲对象入队,这里主要是判断是否是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);
}
这里比较关键的点是,对象的返还,是先到ConcurrentHashMap中找到对象,并且标示它的状态,最后转换为IDLE,最后返还给IDLE队列中。也就是说ConcurrentHashMap维护了所有的对象,而IDLE队列只是维护空闲的对象。
这样整个Commons-pool主干流程就分析完了,这里其实效果不是太好,最好是结合JedisPool和DBCP来看,同时也有一些边角的东西不能完全看到,如果有遗漏的东西,还请指出。