版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq447995687/article/details/80444627
commons-pool2源码走读(三) 对象池BaseGenericObjectPool<T>
BaseGenericObjectPool<T>为GenericObjectPool和GenericKeyedObjectPool提供通用功能的基类。这个类存在的主要原因是减少两个池实现之间的代码复制。
1. 属性加载
BaseGenericObjectPool<T> 定义了所有能够自定义的属性,在类进行初始化的时候设置属性的默认值为BaseObjectPoolConfig和GenericKeyedObjectPoolConfig的默认值。然后子类通过继承其set方法重新覆盖(或延用)默认值。
其属性定义如下,可以看到所有的属性都是volatile的私有变量(fairness除外,在初始化指定后不再变化)。因为属性的变化不依赖之前的值,相较于使用锁而言使用volatile更加快捷高效。
// 最大连接数,默认-1,当值为负数,使用Integer.MAX_VALUE代替
private volatile int maxTotal =
GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
//当活跃对象总数达到上限,继续调用borrowObject是是否阻塞,默认true阻塞
private volatile boolean blockWhenExhausted =
BaseObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED;
//等待连接的超时时间,当blockWhenExhausted =ture,超过该值还未获得对象抛出异常。
private volatile long maxWaitMillis =
BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS;
//是否使用先进先出策略,默认true
private volatile boolean lifo = BaseObjectPoolConfig.DEFAULT_LIFO;
//是否使用平锁,默认false
private final boolean fairness;
//在创建对象的时候测试该对象,默认false
private volatile boolean testOnCreate =
BaseObjectPoolConfig.DEFAULT_TEST_ON_CREATE;
//在借用对象的时候测试该对象,默认false
private volatile boolean testOnBorrow =
BaseObjectPoolConfig.DEFAULT_TEST_ON_BORROW;
//在归还对象的时候测试该对象,默认false
private volatile boolean testOnReturn =
BaseObjectPoolConfig.DEFAULT_TEST_ON_RETURN;
//在对象空闲的时候测试该对象,默认false
private volatile boolean testWhileIdle =
BaseObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE;
//回收线程的执行周期,即多长时候执行一次空闲对象检测。单位是毫秒数。
//如果小于等于0,则不执行检测线程。默认值是-1;
private volatile long timeBetweenEvictionRunsMillis =
BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
//回收线程每次回收时检测的空闲对象个数,即可能不是每个空闲对象都会进行检测是否能够被回收
//当值>=0时,取该数与空闲对象总数的较小值。<0时:空闲总数/该值绝对值,并向上取整。默认3
private volatile int numTestsPerEvictionRun =
BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
//空闲对象被回收的最小空闲时间,默认30分钟,空闲时间超过30分钟的对象将被回收线程强制回收,
//不会保留最小的空闲对象数量
private volatile long minEvictableIdleTimeMillis =
BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
//也是空闲对象被回收的时间,与minEvictableIdleTimeMillis不同的是当空闲数量<最小空闲数量要求时,
//如果回收线程检测到该对象,既使该对象的超时时间已溢出,但是也不会被回收。
//这个之后对EvictionPolicy做详细说明。默认-1
private volatile long softMinEvictableIdleTimeMillis =
BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
//回收策略,根据minEvictableIdleTimeMillis和softMinEvictableIdleTimeMillis
//以及minIdle参数判断对象是否能够被回收
private volatile EvictionPolicy<T> evictionPolicy;
//shutdown一个回收线程的超时时间,在创建回收线程的时候,如果发现已有一个回收线程,
//会将当前回收线程shutdown,并重新开启一个回收线程。默认10s
private volatile long evictorShutdownTimeoutMillis =
BaseObjectPoolConfig.DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT_MILLIS;
其它属性,用于同步操作的锁和对象池的计数信息。
// 对象锁,用于子类
final Object closeLock = new Object();
//标识池是否关闭,用于子类。volatile 线程安全
volatile boolean closed = false;
//初始化回收线程时使用的对象锁
final Object evictionLock = new Object();
//回收线程
private Evictor evictor = null; // @GuardedBy("evictionLock")
EvictionIterator evictionIterator = null; // @GuardedBy("evictionLock")
private final WeakReference<ClassLoader> factoryClassLoader;
//jmxObjectName
private final ObjectName oname;
//调用堆栈
private final String creationStackTrace;
//总借出次数
private final AtomicLong borrowedCount = new AtomicLong(0);
////总归还次数
private final AtomicLong returnedCount = new AtomicLong(0);
//总创建次数
final AtomicLong createdCount = new AtomicLong(0);
//总创销毁次数
final AtomicLong destroyedCount = new AtomicLong(0);
//总被回收销毁次数
final AtomicLong destroyedByEvictorCount = new AtomicLong(0);
//总借用时校验不通过而被销毁次数
final AtomicLong destroyedByBorrowValidationCount = new AtomicLong(0);
//一个存放对象存活时间的缓存类,下面的几个StatsStore 类似
private final StatsStore activeTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
private final StatsStore idleTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
private final StatsStore waitTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
//借用对象时的最大等待时间
private final AtomicLong maxBorrowWaitTimeMillis = new AtomicLong(0L);
private volatile SwallowedExceptionListener swallowedExceptionListener = null;
2. 初始化
构造函数初始化jmx、创建堆栈、factoryClassLoader和fairness
public BaseGenericObjectPool(final BaseObjectPoolConfig config,
final String jmxNameBase, final String jmxNamePrefix) {
//设置并注册jmx
if (config.getJmxEnabled()) {
this.oname = jmxRegister(config, jmxNameBase, jmxNamePrefix);
} else {
this.oname = null;
}
// 创建堆栈
this.creationStackTrace = getStackTrace(new Exception());
// 初始化factoryClassLoader,将会用于回收线程的初始化
final ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl == null) {
factoryClassLoader = null;
} else {
factoryClassLoader = new WeakReference<>(cl);
}
//设置是否使用公平锁
fairness = config.getFairness();
}
3. 回收线程
为了防止对象池泄漏,强制销毁一些非正常的对象。BaseGenericObjectPool使用TimerTask实现了一个定时回收任务
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() {
final ClassLoader savedClassLoader =
Thread.currentThread().getContextClassLoader();
try {
/**
* 注意factoryClassLoader是WeakReference类型
* 当gc时jvm会回收该对象(直接抛弃),相比于close,以此来确保factoryClassLoader一定能被释放gc掉,
* 因此通过检测factoryClassLoader是否为null,来注销该timer,以保证对象池也能被gc,
* 避免因无法close对象池(timer生成的线程为非守护线程,导致无法被gc回收?待确认)而带来的内存泄漏。
*/
if (factoryClassLoader != null) {
// Set the class loader for the factory
final ClassLoader cl = factoryClassLoader.get();
if (cl == null) {
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);
}
try {
//重新创建空闲对象,确保池中最小空闲连接数量
ensureMinIdle();
} catch (final Exception e) {
swallowException(e);
}
} finally {
// Restore the previous CCL
Thread.currentThread().setContextClassLoader(savedClassLoader);
}
}
}
空闲对象的一个iterator,用于回收线程遍历空闲对象,迭代器模式
class EvictionIterator implements Iterator<PooledObject<T>> {
//空闲对象列表
private final Deque<PooledObject<T>> idleObjects;
//Iterator
private final Iterator<PooledObject<T>> idleObjectIterator;
EvictionIterator(final Deque<PooledObject<T>> idleObjects) {
this.idleObjects = idleObjects;
if (getLifo()) {
idleObjectIterator = idleObjects.descendingIterator();
} else {
idleObjectIterator = idleObjects.iterator();
}
}
/**
* Returns the idle object deque referenced by this iterator.
* @return the idle object deque
*/
public Deque<PooledObject<T>> getIdleObjects() {
return idleObjects;
}
/** {@inheritDoc} */
@Override
public boolean hasNext() {
return idleObjectIterator.hasNext();
}
/** {@inheritDoc} */
@Override
public PooledObject<T> next() {
return idleObjectIterator.next();
}
/** {@inheritDoc} */
@Override
public void remove() {
idleObjectIterator.remove();
}
}
4. IdentityWrapper对象包装器
由池管理的对象的包装器。GenericObjectPool和GenericKeyedObjectPool使用该包装器作为键值来映射PooledObject。这个包装类重写了hashCode,equals确保对象可以作为散列键。
static class IdentityWrapper<T> {
/** Wrapped object */
private final T instance;
/**
* Create a wrapper for an instance.
*
* @param instance object to wrap
*/
public IdentityWrapper(final T instance) {
this.instance = instance;
}
@Override
public int hashCode() {
//使用内存地址作为hashcode值,确保唯一性
return System.identityHashCode(instance);
}
@Override
@SuppressWarnings("rawtypes")
public boolean equals(final Object other) {
return other instanceof IdentityWrapper &&
((IdentityWrapper) other).instance == instance;
}
/**
* @return the wrapped object
*/
public T getObject() {
return instance;
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("IdentityWrapper [instance=");
builder.append(instance);
builder.append("]");
return builder.toString();
}
}
finally
由上可以看见BaseGenericObjectPool总共做了一下几件事,并未子类提供了公共的功能模块:
- 默认属性配置
- 对象池的计数信息
- 一个回收(驱逐)线程
- 实现了空闲对象的迭代器
- 注册jmx
- 定义IdentityWrapper作为保存所有对象的map容器的key值