commons-pool学习笔记Object pool就是一个管理对象的池子。新版本利用jdk 1.5以后的特性,结合泛型,而不是利用Object来实现了。 主要就靠3个接口来管理: ObjectPool, 定义了池接口,就是说,以后的对象池,至少模子是这个样子的~~主要两个实现抽象类:BaseObjectPool和KeyedObjectPool。有一些基本方法比如从对象池取对象,调用borrowObject()方法,将对象放回使用returnObject()方法。清空选择clear,而不需要对象池选择关闭时使用close等。在具体的Pool实现中,会依赖PoolableObjectFactory接口。 PoolableObjectFactory,怎么理解这个接口呢?其实在ObjectPool中我们看到只是声明了一些调用和放回对象的方法,可以理解为真正我们在操作一个pool,这就是一个数据结构。然而pool中的对象创建、管理、销毁等事务pool管不了了。因此框架又定义了这样一个factory去管理这些对象。该接口有makeObject方法,我们自己的factory实现里可以利用这个方法去创建个性化的对象。有创建就有销毁,destroyObject(T obj)方法就用来销毁对象。同时还有activateObject(T obj)方法用来激活对象,也就是说令对象可用。有passivateObject(T obj)方法用来将对象作为idle状态。同时还有validateObject(T obj)方法来检验对象是否可以由pool安全返回。 ObjectPoolFactory,作为最后一个接口,我感觉这个factory应该算是用处不特别大吧。顾名思义,用来管理pool的一个factory。我们的应用如果需要的话,可能不止一个pool。由一个factory去管理,明显合理的,而且factory模式也是pool框架的特色。该接口只有一个方法,那就是createObjectPool()。
框架的类图主要关系就是这样 图片来源是http://commons./pool/guide/classdiagrams.html。只需要看清楚几个接口的关系就可以了。 那么最好还是举例看看一个pool如何使用吧。例子是commons-pool1.4版本,jdk1.6 <代码修改自参考资料http://www.ibm.com/developerworks/cn/java/l-common-pool/> 首先定义一个对象(一般使用线程池的原则是对象比较大,所以我们就叫它大对象): 1: /** 2: * 3: */ 4: package common.pool; 5: 6: /** 7: * @author Administrator 8: * 9: */ 10: public class BigObject { 11: 12: private boolean active; 13: 14: public boolean isActive() { 15: return active; 16: } 17: 18: public void setActive(boolean active) { 19: this.active = active; 20: } 21: 22: public BigObject() { 23: active = true; 24: System.out.println("i am a big object!!!"); 25: } 26: 27: public String toString() { 28: return "big object "+ this.hashCode(); 29: } 30: } 接着去实现PoolableObjectFactory: 1: /** 2: * 3: */ 4: package common.pool; 5: 6: import org.apache.commons.pool.*; 7: /** 8: * @author Administrator 9: * 10: */ 11: public class TestFactory implements PoolableObjectFactory{ 12: 13: @Override 14: public void activateObject(Object arg0) throws Exception { 15: // TODO Auto-generated method stub 16: ((BigObject)arg0).setActive(true); 17: } 18: 19: @Override 20: public void destroyObject(Object arg0) throws Exception { 21: // TODO Auto-generated method stub 22: arg0 = null; 23: } 24: 25: @Override 26: public Object makeObject() throws Exception { 27: // TODO Auto-generated method stub 28: BigObject bo = new BigObject(); 29: return bo; 30: } 31: 32: @Override 33: public void passivateObject(Object arg0) throws Exception { 34: // TODO Auto-generated method stub 35: ((BigObject)arg0).setActive(false); 36: } 37: 38: @Override 39: public boolean validateObject(Object arg0) { 40: // TODO Auto-generated method stub 41: if(((BigObject)arg0).isActive()) 42: return true; 43: else 44: return false; 45: } 46: 47: } 最后测试: 1: /** 2: * 3: */ 4: package common.pool; 5: 6: import org.apache.commons.pool.ObjectPool; 7: import org.apache.commons.pool.PoolableObjectFactory; 8: import org.apache.commons.pool.impl.StackObjectPool; 9: 10: 11: /** 12: * @author Administrator 13: * 14: */ 15: public class PoolTest { 16: 17: /** 18: * @param args 19: */ 20: public static void main(String[] args) { 21: // TODO Auto-generated method stub 22: BigObject bo = null; 23: PoolableObjectFactory factory = new TestFactory(); 24: ObjectPool pool = new StackObjectPool(factory); 25: try { 26: for(long i = 0; i < 10 ; i++) { 27: System.out.println("== " + i + " =="); 28: bo = (BigObject) pool.borrowObject(); 29: System.out.println(bo); 30: System.out.println(pool.getNumActive()); 31: if((i&1)==0) { 32: pool.returnObject(bo); 33: } 34: } 35: // bo = null;//明确地设为null,作为对象已归还的标志 36: } 37: catch (Exception e) { 38: e.printStackTrace(); 39: } 40: finally { 41: try{ 42: if (bo != null) {//避免将一个对象归还两次 43: pool.returnObject(bo); 44: } 45: pool.close(); 46: } 47: catch (Exception e){ 48: e.printStackTrace(); 49: } 50: } 51: 52: } 53: 54: } 55: 结束了,一个pool的简单应用就搞定了。下面我们看看代码的具体实现是什么。 先看看pool构造时候都做了些什么: StackObjectPool里有两个protected field,一个protected PoolableObjectFactory _factory = null;一个protected Stack _pool = null;。前者是通过构造方法注入的一个factory,我们的代码里已经自己实现了一个TestFactory;后者是具体的Pool管理策略,像StackObjectPool的话就是内部用这样一个Stack来管理对象。 构造时会通过 1: public StackObjectPool(PoolableObjectFactory factory, int maxIdle, int initIdleCapacity) { 2: _factory = factory; 3: _maxSleeping = (maxIdle < 0 ? DEFAULT_MAX_SLEEPING : maxIdle); 4: int initcapacity = (initIdleCapacity < 1 ? DEFAULT_INIT_SLEEPING_CAPACITY : initIdleCapacity); 5: _pool = new Stack(); 6: _pool.ensureCapacity( initcapacity > _maxSleeping ? _maxSleeping : initcapacity); 7: } 来完成初始参数和变量的构造。 接着我们开始从pool中取对象了,调用borrowObject的方法,具体实现在源码中是这样的: 1: public synchronized Object borrowObject() throws Exception { 2: assertOpen(); 3: Object obj = null; 4: boolean newlyCreated = false; 5: while (null == obj) { 6: if (!_pool.empty()) { 7: obj = _pool.pop(); 8: } else { 9: if(null == _factory) { 10: throw new NoSuchElementException(); 11: } else { 12: obj = _factory.makeObject(); 13: newlyCreated = true; 14: if (obj == null) { 15: throw new NoSuchElementException("PoolableObjectFactory.makeObject() returned null."); 16: } 17: } 18: } 19: if (null != _factory && null != obj) { 20: try { 21: _factory.activateObject(obj); 22: if (!_factory.validateObject(obj)) { 23: throw new Exception("ValidateObject failed"); 24: } 25: } catch (Throwable t) { 26: try { 27: _factory.destroyObject(obj); 28: } catch (Throwable t2) { 29: // swallowed 30: } finally { 31: obj = null; 32: } 33: if (newlyCreated) { 34: throw new NoSuchElementException( 35: "Could not create a validated object, cause: " + 36: t.getMessage()); 37: } 38: } 39: } 40: } 41: _numActive++; 42: return obj; 43: } 在不考虑同步的时候,我们只看对象的创建,典型的几个if逻辑就完成了这样的功能,在pool空时,就用factory的makeObject方法,不空则直接从内置stack里pop一个对象出来。接着在对象构造OK后,开始激活这个对象。接着调用validate去校验,如果不合格就跑出异常,而异常的捕获中又会尝试去destroy对象,再有问题的话只有swallow掉异常了。整个pool会有一个_numActive变量来控制活着(被borrow但没被return)的对象数,每次borrow后都会加一。而循环是到obj不空时才退出的,所以obj不会为null。所以,只要你的makeObject合理的不返回null,那么这个逻辑就不会死循环。当然整个过程中似乎都会有多线程安全问题,所以整个方法都加同步。但是这显然不是完美的解决方法,对于复杂的多线程问题,调度还需要程序员自己来控制。 接着就是returnObject了,顾名思义就是把从pool中借出来的object还回去。逻辑代码如下: 1: public synchronized void returnObject(Object obj) throws Exception { 2: boolean success = !isClosed(); 3: if(null != _factory) { 4: if(!_factory.validateObject(obj)) { 5: success = false; 6: } else { 7: try { 8: _factory.passivateObject(obj); 9: } catch(Exception e) { 10: success = false; 11: } 12: } 13: } 14: 15: boolean shouldDestroy = !success; 16: 17: _numActive--; 18: if (success) { 19: Object toBeDestroyed = null; 20: if(_pool.size() >= _maxSleeping) { 21: shouldDestroy = true; 22: toBeDestroyed = _pool.remove(0); // remove the stalest object 23: } 24: _pool.push(obj); 25: obj = toBeDestroyed; // swap returned obj with the stalest one so it can be destroyed 26: } 27: notifyAll(); // _numActive has changed 28: 29: if(shouldDestroy) { // by constructor, shouldDestroy is false when _factory is null 30: try { 31: _factory.destroyObject(obj); 32: } catch(Exception e) { 33: // ignored 34: } 35: } 36: } 首先一个success变量作为判断位来决定对象能否放回pool。如果经过validate后发现对象不合格,那么显然不能放回pool了。如果validate合格,那么就尝试用factory的passivateObject方法使对象变为not active。接着进入逻辑判断如果可以放回,那么尝试将对象push到pool的内置stack中,尝试时会有阈值限定,如果超过了阈值的话,那么需要以某种策略将stack中的对象remove掉一个。而策略如果仔细看代码就会发现很合理,首先在stack中remove最老的一个,然后将这个remove值保存为临时变量,将待放回对象push到stack,接着将临时对象转接到带放回对象上。我们看到,这样的一组行为保证了几个对象的销毁,而不会出现内存泄露。 最后附上apache官网上的几张时序图来完美解释borrow和return的过程: 基本介绍到此,后续可能有进阶研究,期待时间~~ 参考资料: http://www.ibm.com/developerworks/cn/java/l-common-pool/ posted on 2011-05-06 10:53 changedi 阅读(4659) 评论(6) 编辑 收藏 所属分类: Java技术 |
|