commons-pool2原始碼走讀(三) 抽象物件池BaseGenericObjectPool
阿新 • • 發佈:2018-12-31
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值