在java开发中,为了减少对象创建和销毁的开销,我们常常复用对象,如单例模式。在同时需要多个对象时,则采用池,如线程池、数据库连接池等。这里介绍基于apache的commons-pool2包来创建自定义的对象池。
官网地址:http://commons.apache.org/proper/commons-pool/
org.apache.commons
commons-pool2
2.4.2
org.apache.commons.pool2.PooledObjectFactory,用于对象的创建、激活、钝化、销毁等操作。
org.apache.commons.pool2.impl.DefaultPooledObject,对实际对象进行包装,添加如状态等信息。
org.apache.commons.pool2.impl.GenericObjectPool,对象池。
org.apache.commons.pool2.impl.GenericObjectPoolConfig,用于控制如最大连接数,最大空闲数、最小空闲数等。
commons-pool2包的对象池是线程安全的。
所有对象存在ConcurrentHashMap中;
空闲对象存在LinkedBlockingDeque中。位org.apache.commons.pool2.impl.GenericObjectPool类中的关键源码如下:
// --- configuration attributes --------------------------------------------
private volatile int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE;
private volatile int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE;
private final PooledObjectFactory<T> factory;
// --- internal attributes -------------------------------------------------
/*
* All of the objects currently associated with this pool in any state. It
* excludes objects that have been destroyed. The size of
* {@link #allObjects} will always be less than or equal to {@link
* #_maxActive}. Map keys are pooled objects, values are the PooledObject
* wrappers used internally by the pool.
*/
private final Map<IdentityWrapper<T>, PooledObject<T>> allObjects =
new ConcurrentHashMap<IdentityWrapper<T>, PooledObject<T>>();
/*
* The combined count of the currently created objects and those in the
* process of being created. Under load, it may exceed {@link #_maxActive}
* if multiple threads try and create a new object at the same time but
* {@link #create()} will ensure that there are never more than
* {@link #_maxActive} objects created at any one time.
*/
private final AtomicLong createCount = new AtomicLong(0);
private final LinkedBlockingDeque<PooledObject<T>> idleObjects;
// JMX specific attributes
private static final String ONAME_BASE =
"org.apache.commons.pool2:type=GenericObjectPool,name=";
// Additional configuration properties for abandoned object tracking
private volatile AbandonedConfig abandonedConfig = null;
这里创建示例对象Link,如下:
/**
* 池中的对象(示例)
*/
@Data
static class Link {
private String url;
public Link(String url) {
this.url = url;
}
}
实现接口PooledObjectFactory,接口包含对象创建、激活、钝化、销毁、验证对象是否安全等方法,示例如下:
/**
* 池对象工厂,对对象的操作
*/
static class LinkPooledObjectFactory implements PooledObjectFactory<Link> {
private String url;
public LinkPooledObjectFactory() {
}
public LinkPooledObjectFactory(String url) {
this.url = url;
}
/**
* 当需要新对象时调用,创建对象
*
* @return
* @throws Exception
*/
@Override
public PooledObject<Link> makeObject() throws Exception {
System.out.println("makeObject");
Link o = new Link(url);
//用DefaultPooledObject包裹创建的对象,用于跟踪对象的状态
return new DefaultPooledObject<>(o);
}
/**
* 不再需要对象时调用,销毁对象
*
* @param p
* @throws Exception
*/
@Override
public void destroyObject(PooledObject<Link> p) throws Exception {
System.out.println("destroyObject");
Link o = p.getObject();
o = null;
}
/**
* 从池中取对象或归还对象到池中时,判断对象安全
*
* @param p
* @return
*/
@Override
public boolean validateObject(PooledObject<Link> p) {
System.out.println("validateObject");
return false;
}
/**
* 从池中取出对象,使用前,再次初始化对象
*
* @param p
* @throws Exception
*/
@Override
public void activateObject(PooledObject<Link> p) throws Exception {
System.out.println("activateObject");
}
/**
* 当对象返回到空闲池时调用,钝化对象
*
* @param p
* @throws Exception
*/
@Override
public void passivateObject(PooledObject<Link> p) throws Exception {
System.out.println("passivateObject");
}
}
实现接口GenericObjectPool, 示例如下:
/**
* 对象池
*/
static class LinkPool extends GenericObjectPool<Link> {
public LinkPool(PooledObjectFactory<Link> factory) {
super(factory);
}
public LinkPool(PooledObjectFactory<Link> factory, GenericObjectPoolConfig config) {
super(factory, config);
}
public LinkPool(PooledObjectFactory<Link> factory, GenericObjectPoolConfig config, AbandonedConfig abandonedConfig) {
super(factory, config, abandonedConfig);
}
}
对象池配置,包含最大对象数、最大空闲对象数、最小空闲对象数等配置,示例如下:
//创建对象池配置
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
//最大连接数
config.setMaxTotal(6);
//最大空闲数
config.setMaxIdle(3);
//最小空闲数
config.setMinIdle(1);
//最长等待时间,3秒
config.setMaxWaitMillis(3000);
public static void main(String[] args) throws Exception {
//创建对象池配置
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
//最大连接数
config.setMaxTotal(6);
//最大空闲数
config.setMaxIdle(3);
//最小空闲数
config.setMinIdle(1);
//最长等待时间,3秒
config.setMaxWaitMillis(3000);
//创建对象池工厂
LinkPooledObjectFactory factory = new LinkPooledObjectFactory("hehe");
//创建对象池
LinkPool pool = new LinkPool(factory, config);
//测试
for (int i = 0; i < 8 ; i++) {
//获取对象
Link link = pool.borrowObject();
System.out.println(link);
TimeUnit.SECONDS.sleep(1);
//使用后归还对象
pool.returnObject(link);
}
}
上面列出了基于commons-pools中的使用,更多操作可查看源码。