本文以apache common-pools为例
主要组成类
PooledObject(可被池化的对象)
默认实现DefaultPooledObject,里面封装了一个真正的用户需要池化的对象object。
其中DefaultPooledObject里面有两个方法:
Exception borrowedBy :用于记录上次调用borrow时的堆栈,用于跟踪代码调用情况
@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;
}
Exception usedBy: 同上,记录use时的堆栈
@Override
public void use() {
lastUseTime = System.currentTimeMillis();
usedBy = new Exception("The last code to use this object was:");
}
PooledObjectState
对象的状态,也即生命周期
- allocated :此对象被客户端使用中
- idle :在池中,处于空闲状态
- eviction:在实例化GenericObjectPool对象时,内部会启动一个EvictionTimer线程线程,定期(timeBetweenEvictionRunsMillis)执行evict方法,以EvictionPolicy策略destory 状态处于idle过长的对象或idle数太多的时候。
- abandoned:当池中的对象被客户端拿出后,若长时间(removeAbandonedTimeout)未返回池中,或没有调用use方法,即被标记为抛弃的,当执行removeAbandoned方法时从池中destory,并若logAbandoned为true的话,则打印调用堆栈
PooledObjectFactory(对象创建工厂)
一般需要程序员继承BasePooledObjectFactory,创建需要池化的对象:
private static class ShardedJedisFactory implements PooledObjectFactory<ShardedJedis> {
private List<JedisShardInfo> shards;
private Hashing algo;
private Pattern keyTagPattern;
public ShardedJedisFactory(List<JedisShardInfo> shards, Hashing algo, Pattern keyTagPattern) {
this.shards = shards;
this.algo = algo;
this.keyTagPattern = keyTagPattern;
}
@Override
public PooledObject<ShardedJedis> makeObject() throws Exception {
ShardedJedis jedis = new ShardedJedis(shards, algo, keyTagPattern);
return new DefaultPooledObject<ShardedJedis>(jedis);
}
@Override
public void destroyObject(PooledObject<ShardedJedis> pooledShardedJedis) throws Exception {
final ShardedJedis shardedJedis = pooledShardedJedis.getObject();
for (Jedis jedis : shardedJedis.getAllShards()) {
if (jedis.isConnected()) {
try {
try {
jedis.quit();
} catch (Exception e) {
}
jedis.disconnect();
} catch (Exception e) {
}
}
}
}
@Override
public boolean validateObject(PooledObject<ShardedJedis> pooledShardedJedis) {
try {
ShardedJedis jedis = pooledShardedJedis.getObject();
for (Jedis shard : jedis.getAllShards()) {
if (!shard.ping().equals("PONG")) {
return false;
}
}
return true;
} catch (Exception ex) {
return false;
}
}
@Override
public void activateObject(PooledObject<ShardedJedis> p) throws Exception {
}
@Override
public void passivateObject(PooledObject<ShardedJedis> p) throws Exception {
}
}
GenericObjectPoolConfig(对象池配置)
- lifo:后进先出,或者先进先出
- maxWaitMillis:从idle队列里面取对象时,若阻塞的话,则最大等待时长
- minEvictableIdleTimeMillis:处于idle状态超过此值时,会被destory
- softMinEvictableIdleTimeMillis:处于idle状态超过此值,且处于idle状态个数大于minIdle时会被destory ,正常情况下softMinEvictableIdleTimeMillis < minEvictableIdleTimeMillis
- numTestsPerEvictionRun: evict线程每次遍历时evict的个数
- testOnCreate:当create对象时,是否测试池化的对象是否存活
- testOnBorrow: 同上,从池中borrow出来时测试
- testOnReturn:同上,归还池中时测试
- testWhileIdle:同上,idle状态时测试
- timeBetweenEvictionRunsMillis:evict线程每次间隔时间
- blockWhenExhausted:从池中取对象时,若池子用尽的话,是否阻塞等待一会maxWaitMillis
- jmxEnabled:jmx是否开启监控
AbandonedConfig(防止对象泄露)
- abandoned:被抛弃的,即被池抛弃的设置(客户端从池里面取出去后,若长时间不归还池中,则抛弃并destory)并通过配置可以设置是否logAbandoned,若true的话,则把抛弃对象时,打印相关的日志(调用日志)
主要流程
evict线程流程