对象池模式
一种特殊的工厂对象,一个对象池包含一组已经初始化过且可以使用的对象。用户可以从池中取得对象,并对其进行操作,在不需要的时候将其归还给对象池。
使用对象池的目的是为了提升性能,当需要创建比较耗费时间的对象时尤为明显。

角色和职责
对象池的管理者
管理者来维护对象池,包括初始化对象池、扩充对象池的大小、获取对象时的策略、重置归还对象的状态。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 
 | public class PoolMgr{
 private int init ;
 
 private int max;
 
 private int factor;
 
 private Colection c;
 
 public void init(){
 
 }
 
 
 public Object aquire(){
 
 return c.remove();
 }
 
 public void release(Object o){
 if(o == null) return;
 
 reset(o);
 c.add(o);
 }
 
 }
 
 | 
对象池的使用者
使用者从管理者处获取对象,使用完成后必须归还对象避免一致占用。
| 12
 3
 4
 5
 6
 
 | Object o = null;try{
 o = PoolMgr.getInstance();
 }finaly{
 PoolMgr.release(o);
 }
 
 | 
优点
复用池中的对象,消除创建/回收对象所产生的内存开销,CPU开销以及IO开销。
常见的有:Socket的链接池、线程池、数据库连接池等。
缺点
多线程并发环境中,需要考虑线程安全问题,需要在数据结构上进行同步或者为锁竞争产生阻塞,这种开销处理不好会比创建销毁独享的开销高很多。
由于池中的对象数量有限,对象池小可能会成为性能瓶颈,太大占用内存资源高;
轻量级对象的创建/销毁不需要使用对象池,徒增系统的复杂度;
Common Pool2
Commons Pool2核心部分由三个基础接口和相关的实现类实现:
PooledObject
池化对象,对池中的对象进行封装,封装对象的状态和一些其他信息。
PooldedObject 有两个实现类,DefaultPoolObject时普通通用的实现,PooledSoftReference使用SoftReference封装了对象,供SoftReferenceObjectPool使用。

| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 
 | public interface PooledObject<T> extends Comparable<PooledObject<T>> {
 T getObject();
 
 
 long getCreateTime();
 
 
 long getActiveTimeMillis();
 
 
 long getIdleTimeMillis();
 
 
 long getLastBorrowTime();
 
 
 long getLastReturnTime();
 
 
 long getLastUsedTime();
 
 
 void invalidate();
 
 
 void use();
 
 
 PooledObjectState getState();
 
 
 void markAbandoned();
 
 
 void markReturning();
 }
 
 | 
PooledObjectFactory
 池化对象工厂,负责对象的创建、初始化、销毁和验证工作,Factory对象由ObjectPool持有并使用。
因为对象的创建、初始化、销毁和仰正的工作无法通用,Commons Pool2并没有提供PooledObjectFactory的默认子类实现,只提供了抽象子类BasePooledObjectFactory
可以实现create和wrap两个方法。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | public interface PooledObjectFactory<T> {
 PooledObject<T> makeObject() throws Exception;
 
 
 void destroyObject(PooledObject<T> p) throws Exception;
 
 
 boolean validateObject(PooledObject<T> p);
 
 
 void activateObject(PooledObject<T> p) throws Exception;
 
 
 void passivateObject(PooledObject<T> p) throws Exception;
 }
 
 | 
ObjectPool
 持有对象并提供取/还等操作.
 | 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 |  public interface ObjectPool<T> {// 从池中获取一个对象,客户端在使用完对象后必须使用 returnObject 方法返还获取的对象
 T borrowObject() throws Exception, NoSuchElementException,
 IllegalStateException;
 
 // 将对象返还到池中。对象必须是从 borrowObject 方法获取到的
 void returnObject(T obj) throws Exception;
 
 // 使池中的对象失效,当获取到的对象被确定无效时(由于异常或其他问题),应该调用该方法
 void invalidateObject(T obj) throws Exception;
 
 // 池中当前闲置的对象数量
 int getNumIdle();
 
 // 当前从池中借出的对象的数量
 int getNumActive();
 
 // 清除池中闲置的对象
 void clear() throws Exception, UnsupportedOperationException;
 
 // 关闭这个池,并释放与之相关的资源
 void close();
 
 ...
 }
 
 | 
对象池配置
对象池配置提供了对象池初始化所需要的参数,Common Pool2中的基础配置类时BaseObjectPoolConfig, 有GenericObjectPoolConfig和GenericKeyedObjectPoolConfig,分别为GenericObjectPool和GenericKeyedObjectPool使用。
| 参数 | 解释 | 默认值 | 
| lifo | 连接池存放池对象的方式; true:放在空闲队列的嘴钱买呢, false:放在空闲队列的最后面 | true | 
| fairness | 从池中获取/返还对象时是否使用公平锁机制 | false | 
| maxWaitMillis | 获取资源的等待时间。blockWhenExhausted为true时有效。-1代表无时间限制,一致阻塞到有可用的资源 |  | 
| minEvictableIdleTimeMillis | 对象空闲的最小时间,打到此值后空闲对象可能会被移除,-1表示不移除 | 30分钟 | 
| softMinEvictableIdletimeMillis | 对象空闲的最小时间,并且池中之少保留有minidle所指定的个数 |  | 
| numTestsPerEvictionRun | 资源回收线程执行一次回收操作回收资源的个数 | 3 | 
| evictionPolicyClassName | 资源回收策略 | org.apache.commons.pool2.impl.DefaultEvictionPolicy | 
| testOnCreate | 创建对象时是否调用factory.validateObject | false | 
| testOnBorrow | 获取对形势是否调用factory.validateObject | false | 
| testOnReturn | 返还对象时是否调用factory.validateObject | false | 
| timeBetweenEvictionRunsMills | 回收资源线程的执行周期,默认-1表示不启用回收资源线程 | -1 | 
| blockWhenExhausted | 资源耗尽时,是否阻塞等待获取资源 | true | 
| testWhileIdel | 池中的限制对象是否由逐出器验证,无法验证的对象将从池中删除销毁 | false | 
池化对象的状态
| 参数值 | 描述 | 
| IDEL | 在池中,处于空闲状态 | 
| ALLOCATED | 被使用中 | 
| EVICTION | 正在被逐出器验证 | 
| VALIDAITTON | 正在验证 | 
| INVALID | 驱逐测试或者验证失败并将被销毁 | 
| ABANDONED | 对象被客户端拿出后,长时间未返回池中,或者没有调用use方法,被标记为抛弃 | 
Demo
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 
 | public class StringBufferFactory extends BasePooledObjectFactory<StringBuffer> {
 @Override
 public StringBuffer create() {
 return new StringBuffer();
 }
 
 
 @Override
 public PooledObject<StringBuffer> wrap(StringBuffer buffer) {
 return new DefaultPooledObject<>(buffer);
 }
 
 
 @Override
 public void passivateObject(PooledObject<StringBuffer> pooledObject) {
 pooledObject.getObject().setLength(0);
 }
 }
 
 | 
使用
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 
 |  GenericObjectPoolConfig config = new GenericObjectPoolConfig();
 
 PooledObjectFactory factory = new StringBufferFactory();
 
 ObjectPool<StringBuffer> pool = new GenericObjectPool<>(factory, config);
 StringReader in = new StringReader("abcdefg");
 StringBuffer buf = null;
 try {
 
 buf = pool.borrowObject();
 
 
 for (int c = in.read(); c != -1; c = in.read()) {
 buf.append((char) c);
 }
 return buf.toString();
 } catch (Exception e) {
 try {
 
 pool.invalidateObject(buf);
 
 buf = null;
 } catch (Exception ex) {
 
 }
 throw e;
 } finally {
 try {
 in.close();
 } catch (Exception e) {
 
 }
 
 try {
 if (null != buf) {
 
 pool.returnObject(buf);
 }
 } catch (Exception e) {
 
 }
 }
 
 | 
参考:
Apache Common Pool2 对象池应用浅析
一个广为人知但鲜有人用的技巧:对象池