一、摘要
apache common pool2 作为对象池模式的一种实现,通过重用来分摊复杂对象的创建代价。被广泛应用在各种数据库连接池,线程池以及请求分发池中;其实现提供了一些参数来控制对象池的行为,了解这些参数对学习其他“池”技术很有必要。
二、对象池
对象池模式解决的问题:
管理那些代表的现实资源或者通过重用来分摊昂贵初始化代价的对象。
对象的创建和销毁在一定程度上会消耗系统的资源,虽然jvm的性能在近几年已经得到了很大的提高,对于多数对象来说,没有必要利用对象池技术来进行对象的创建和管理。但是对于有些对象来说,其创建的代价还是比较昂贵的,比如线程、tcp连接、数据库连接等对象,因此对象池技术还是有其存在的意义。
对象池模式:
对象池模式管理一个可代替对象的集合。组件从池中借出对象,用它来完成一些任务并当任务完成时归还该对象。被归还的对象接着满足请求,不管是同一个组件还是其他组件的请求。
对象池模式优缺点
- 优点; 复用池中对象,没有分配内存和创建堆中对象的开销, 没有释放内存和销毁堆中对象的开销, 进而减少垃圾收集器的负担, 避免内存抖动;不必重复初始化对象状态。
- 缺点:
1. 并发环境下,对象池操作的同步成为一大开销;
2. 很难正确设置对象池大小,太小不起作用,太大浪费资源。
三、 common pool2 核心
Apache Common-pool2包提供了一个通用的对象池技术的实现。可以很方便的基于它来实现自己的对象池,比如DBCP和Jedis他们的内部对象池的实现就是依赖于Common-pool2。
Common-pool2由三大模块组成:ObjectPool
、PooledObject
和PooledObjectFactory
。
它们的关系如下:
- ObjectPool:提供所有对象的存取管理。
- PooledObject:池化的对象,是对真正对象的一个包装,加上了对象的一些其他信息,包括对象的状态(已用、空闲),对象的创建时间等。其实现要求是线程安全的。
- PooledObjectFactory:工厂类,负责池化对象的创建,对象的初始化,对象状态的销毁和对象状态的验证。其实现要求是线程安全的。
通常,ObjectPool会持有PooledObjectFactory,将具体的对象的创建、初始化、销毁等任务委托给PooledObjectFactory处理,工厂操作的对象是PooledObject,即具体的Object的包装类。因此,获取对象依赖ObjectPool而不是PooledObjectFactory。
池化对象于真正对象的区别
ObjectPool提供出去的对象是真正对象,而不是池化对象;池化对象是对象池的概念,为管理真正对象的相关细节提供支持。
PooledObject的实现会组合真正的对象。
PooledObjectFactory工厂产生的也是池化对象,而不是真正对象。
自定义对象池
以上三个抽象组件定义了 apache common pool2的标准,自定义对象池分别实现这三个抽象组件:
- ObjectPool的实现,主要提供borrow/return池化对象,调用者可直接使用,或者通过组合的方式使用对象池。
- PooledObjectFactory的实现,用以产生池化对象。
- PooledObject的实现,包装真正对象。
apache common pool2也提供了自己的对象池实现来简化开发,自定义对象池完全可以依赖这个实现获得强大的对象池功能。
四、common pool2 自带实现
apache common pool2提供了一些实现。这里介绍一种被广泛使用的实现:
- ObjectPool的实现:GenericObjectPool,提供了一个功能强大的对象池。
- PooledObject的实现:DefaultPooledObject
- PooledObjectFactory的实现:不可能提供默认实现,因为涉及到具体对象的创建,需要使用者本身去实现。但是为了简化开发,提供了一个抽象的
BasePooledObjectFactory
,使用者可以选择实现这个抽象类,而不是PooledObjectFactory来提供自己的池化对象工厂。
主要是对象池GenericObjectPool
的实现,主要介绍其borrow和return池化对象的方法。
GenericObjectPool
- Map<IdentityWrapper<T>, PooledObject<T>> allObjects
- LinkedBlockingDeque<PooledObject<T>> idleObjects
主要使用以上两个数据结构保持池化对象。
borrow的流程
- 从idle队列取出第一个池化对象
- 若池化对象为null,尝试使用工厂创建一个池化对象
- 创建若createCount小于maxTotal,则使用工厂新建池化对象,否则返回null
- blockWhenExhausted只是idle为空时是否等待,maxWaitMillis只是等待多久
- 池化对象!=null;factory#activateObject
- testOnBorrow || (create && testOnCreate) factory#validateObject
return的流程
- 根据obj从allObjects取出polledObject p
- 判空;将p状态置为RETURN
- 若getTestOnReturn参数为true,进行factory#validateObject
- 对p进行factory#passivateObject,与初始化相反
- 更新p状态为IDLE
- 归还Pool:Pool的idle实例达到上限或者Pool已经关闭,销毁之,否则将p加入到LinkedBlockingDeque中。
自定义对象池可以依赖GenericObjectPool以及DefaultPooledObject,只实现PooledObjectFactory即可。
对象池属性
org.apache.commons.pool2.impl.GenericObjectPool
对象池属性,控制对象池产生对象的行为;
全部属性由org.apache.commons.pool2.impl.BaseGenericObjectPool
描述:
属性 | 值 | 说明 |
---|---|---|
borrow: | ||
maxTotal | long;默认-1 | idle队列为空,idle.len < maxTotal可创建,-1时maxTotal为整数最大值 |
blockWhenExhausted | true[默认]/false | idle空,maxTotal达到,是否等待队列 |
maxWaitMillis | long;默认-1 | idle空,maxTotal达到blockWhenExhausted=true,等待队列时长;-1一直等 |
testOnBorrow | true/false[默认] | borrow时,控制objFactory#validateObject |
testOnCreate | true/false[默认] | borrow时,通过create获得,控制objFactory#validateObject |
return: | ||
testOnReturn | true/false[默认] | objPool#returnObj,控制 objFactory#validateObject |
lifo | true[默认]/false | true-LIFO idle队列后进先出; false-FIFO idle队列先进先出 |
五、自定义对象池
使用默认对象池GenericObjectPool,只需定义池化对象工厂即可。
官方提供了demo 官方demo
以下为简化,更容易看清本质:
池化对象工厂:产生StringBuffer对象
public class StringBufferFactory extends BasePooledObjectFactory<StringBuffer> {
@Override
public StringBuffer create() throws Exception {
return new StringBuffer();
}
// 直接使用DefaultPooledObject包装真正对象StringBuffer,提供池化对象
@Override
public PooledObject<StringBuffer> wrap(StringBuffer obj) {
return new DefaultPooledObject<>(obj);
}
@Override
public void passivateObject(PooledObject<StringBuffer> p) throws Exception {
p.getObject().setLength(0);
}
}
使用
public static void main(String[] args) throws Exception {
// 直接使用 apache common pool2提供的对象池,将创建池化对象细节委托给自定义的工厂即可。
GenericObjectPool<StringBuffer> pool = new GenericObjectPool<>(new StringBufferFactory());
// 从对象池借真正对象
StringBuffer stringBuffer = pool.borrowObject();
// do something with string buffer.
// 归还
pool.returnObject(stringBuffer);
}
网友评论