分享

commons

 风_宇星 2014-04-30

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()。

 

框架的类图主要关系就是这样

clip_image002

图片来源是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的过程:

clip_image002[4]

clip_image002[6]

基本介绍到此,后续可能有进阶研究,期待时间~~

参考资料:

http://www.ibm.com/developerworks/cn/java/l-common-pool/

http://commons./pool



posted on 2011-05-06 10:53 changedi 阅读(4659) 评论(6)  编辑  收藏 所属分类: Java技术

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多