代码:
1. GenericObjectPool<T>类
对象池核心类,实现了对象池的管理功能。需要两个构造参数PooledObjectFactory和GenericObjectPoolConfig。
public T borrowObject() throws Exception:从对象池获取对象
public void returnObject(T obj):归还对象至对象池
public void preparePool() throws Exception:初始化minIdle个对象
public int getNumActive():获取非空闲对象的个数
public int getNumIdle():获取空闲对象的个数
2. PooledObjectFactory<T>接口
池化对象工厂接口,实现对池化对象的操作。
PooledObject<T> makeObject throws Exception
创建对象,preparePool时调用,池中无空闲对象且未达maxTotal时调用。
void destroyObject(PooledObject<T> p) throws Exception
销毁对象,validateObject对象无效时调用,空闲时间大于minEvictableIdleTimeMillis时调用。
boolean validateObject(PooledObject<T> p)
检测对象是否有效,获取对象和归还对象时调用,对象无效则调用destroyObject。
void activateObject(PooledObject<T> p) throws Exception
激活对象,获取对象时调用,testWhileIdle时空闲对象检测线程调用。一般激活时先validateObject再决定是否需要操作。
void passivateObject(PooledObject<T> p) throws Exception
钝化对象,归还对象时调用,testWhileIdle时空闲对象检测线程activateObject成功后调用。activateObject和passivateObject一般配合使用。
3. GenericKeyedObjectPool<K,T>接口
带key的池化对象工厂接口,每个key对应一个GenericObjectPool,实现对多个对象池的管理。
4. GenericObjectPoolConfig类
对象池配置类。
lifo:对象池存储空闲对象是使用的LinkedBlockingDeque,它本质上是一个支持FIFO和FILO的双向的队列,common-pool2中的LinkedBlockingDeque不是Java原生的队列,而有common-pool2重新写的一个双向队列。如果为true,表示使用FIFO获取对象。默认值是true。构造连接池时可设置为false实现均衡负载。
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。minEvictableIdleTimeMillis大于0时softMinEvictableIdleTimeMillis不生效,建议使用softMinEvictableIdleTimeMillis。
numTestsPerEvictionRun:空闲对象检测线程每次检测的空闲对象的数量。默认值是3;如果这个值小于0,则每次检测的空闲对象数量等于当前空闲对象数量除以这个值的绝对值,并对结果向上取整。
testOnCreate:在创建对象时检测对象是否有效,默认值是false。
testOnBorrow:在从对象池获取对象时是否检测对象有效,默认值是false。
testOnReturn:在向对象池中归还对象时是否检测对象有效,默认值是false。
testWhileIdle:在空闲对象检测线程检测到对象不需要移除时,是否检测对象的有效性。默认值是false。
timeBetweenEvictionRunsMillis:空闲对象检测线程的执行周期,即多长时候执行一次空闲对象检测。单位是毫秒数。如果小于等于0,则不执行检测线程。默认值是-1。
blockWhenExhausted:当对象池没有空闲对象时,新的获取对象的请求是否阻塞。默认值是true。
maxTotal:对象池中管理的最大对象个数。默认值是8。
maxIdle:对象池中最大的空闲对象个数。默认值是8。
minIdle:对象池中最小的空闲对象个数。默认值是0。
源码:
TCP连接池实践:
配置:
1. lifo=false,实现对对多个目标地址的均衡负载。
2. activateObject可留空,或先validateObject再决定是否重连。
3. eviction
实现:
1. 池化对象中封装一个连接对象,一个连接地址对象
public class SocketAddress {
private String address;
private int weight = 5;
private int originWeight = 5;
private AtomicInteger activeCount = new AtomicInteger();
private AtomicInteger errorCount = new AtomicInteger();
public SocketAddress(String address) {
this.address = address;
}
public SocketAddress(String address, Integer weight) {
this.address = address;
this.weight = weight;
this.originWeight = weight;
}
public String getAddress() {
return address;
}
public boolean isActive() {
return weight > 0;
}
public synchronized void incActiveCount() {
activeCount.incrementAndGet();
}
public synchronized void decActiveCount() {
activeCount.decrementAndGet();
}
public boolean isError() {
return errorCount.get() > 1;
}
public synchronized void incErrorCount() {
this.errorCount.incrementAndGet();
}
public void resetErrorCount() {
this.errorCount.set(0);
}
public void activate() {
this.errorCount.set(0);
this.weight = this.originWeight;
}
public void passivate() {
this.weight = 0;
this.errorCount.set(0);
}
public double getWeightedActiveCount() {
return activeCount.get()/(double)weight;
}
@Override
public String toString() {
return "SocketAddress [address=" + address + ", weight=" + weight + ", activeCount=" + activeCount.get()
+ ", errorCount=" + errorCount.get() + "]";
}
}
2. 池化对象工厂中初始化一个连接地址负载均衡器。makeObject时开启连接,使用连接地址负载均衡器获取一个连接地址对象,连接地址对象activeCount+1。destroyObject时关闭连接,连接地址对象activeCount-1。
3. 创建一个定时任务,定时遍历所有连接地址负载均衡器,钝化连续报错的地址,重新激活可连接的地址,并重置相关连接池。