【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
common-pool2策略
上一篇对象池common-pool2分析从三个主要的接口进行分析,这一篇将对源码进行详细的分析,力图找出对象池的管理策略.从之前的分析可以看出ObjectPool定义了对象池需要实现的功能,所以重点分析ObjectPool.
GenericObjectPool:一般对象池
GenericKeyedObjectPool:可以根据key分组的对象池
SoftReferenceObjectPool:软引用对象池.
GenericObjectPool
public GenericObjectPool(PooledObjectFactory<T> factory,
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;
//根据给定的容量和策略创建空闲对象队列,默认容量Integer.MAX_VALUE
//fairness为true时类似FIFO队列
idleObjects = new LinkedBlockingDeque<PooledObject<T>>(config.getFairness());
//设置配置信息
setConfig(config);
//根据给定延迟启动驱逐器
startEvictor(getTimeBetweenEvictionRunsMillis());
}
BaseGenericObjectPool
final void startEvictor(long delay) {
synchronized (evictionLock) {
//如果evictor已经启动则停止
if (null != evictor) {
EvictionTimer.cancel(evictor);
evictor = null;
evictionIterator = null;
}
//当delay即timeBetweenEvictionRunsMillis大于0时根据给定的delay启动新的驱逐器
if (delay > 0) {
evictor = new Evictor();
EvictionTimer.schedule(evictor, delay, delay);
}
}
}
BaseGenericObjectPool内部类Evictor
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() {
ClassLoader savedClassLoader =
Thread.currentThread().getContextClassLoader();
try {
if (factoryClassLoader != null) {
// Set the class loader for the factory
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 {
//调用public abstract void evict() throws Exception;此方法由子类实现.
evict();
} catch(Exception e) {
swallowException(e);
} catch(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 (Exception e) {
swallowException(e);
}
} finally {
// Restore the previous CCL
Thread.currentThread().setContextClassLoader(savedClassLoader);
}
}
}
GenericObjectPool的方法evict()
public void evict() throws Exception {
assertOpen();//确保连接池是打开的
if (idleObjects.size() > 0) {
PooledObject<T> underTest = null;
//获取驱逐策略
EvictionPolicy<T> evictionPolicy = getEvictionPolicy();
synchronized (evictionLock) {
//驱逐配置
EvictionConfig evictionConfig = new EvictionConfig(
getMinEvictableIdleTimeMillis(),
getSoftMinEvictableIdleTimeMillis(),
getMinIdle());
//空闲时检查
boolean testWhileIdle = getTestWhileIdle();
//getNumTests()获取检测的数量
for (int i = 0, m = getNumTests(); i < m; i++) {
if (evictionIterator == null || !evictionIterator.hasNext()) {
if (getLifo()) {//连接池是否是后进先出
//返回倒序的迭代
evictionIterator = idleObjects.descendingIterator();
} else {
evictionIterator = idleObjects.iterator();
}
}
if (!evictionIterator.hasNext()) {
// Pool exhausted, nothing to do here
return;
}
try {
//获取对象
underTest = evictionIterator.next();
} catch (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 (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 (Exception e) {
destroy(underTest);//激活异常则销毁
destroyedByEvictorCount.incrementAndGet();
}
if (active) {//已经激活
if (!factory.validateObject(underTest)) {//验证不通过则销毁
destroy(underTest);
destroyedByEvictorCount.incrementAndGet();
} else {
try {
factory.passivateObject(underTest);//钝化
} catch (Exception e) {
destroy(underTest);
destroyedByEvictorCount.incrementAndGet();
}
}
}
}
if (!underTest.endEvictionTest(idleObjects)) {
// TODO - May need to add code here once additional
// states are used
}
}
}
}
}
AbandonedConfig ac = this.abandonedConfig;
if (ac != null && ac.getRemoveAbandonedOnMaintenance()) {
removeAbandoned(ac);
}
}
GenericKeyedObjectPool
与GenericObjectPool类似,只是需要遍历key,根据key获取空闲对象.
SoftReferenceObjectPool
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。SoftReferenceObjectPool没有后台驱逐线程,当内存不足时由虚拟机清除.
来源:oschina
链接:https://my.oschina.net/u/657390/blog/656783