Commons-pool是一个apache开源组织下的众多项目的一个。其被广泛地整合到众多需要对象池功能的项目中。

官网:http://commons.apache.org/proper/commons-pool/

本文是commons-pool的一个简单应用,包括不带key的池和带key的池。带key的池是把key相同的池对象放在一起池里,也就是说有多少个key就有多少个池。

不带key的池是生产完全一致的对象放在池里,但是有时候,单用对池内所有对象一视同仁的对象池,并不能解决的问题。例如,对于一组某些参数设置不同的同类对象――比如一堆指向不同地址的  java.net.URL对象或者一批代表不同语句的java.sql.PreparedStatement对象,用这样的方法池化,就有可能取出不合用 的对象的麻烦。这里对带key的池也做了简单的例子。

Commons-pool将对象池化的工作安排给了三类对象:

1.      PoolableObjectFactory(KeyedPoolableObjectFactory):用于管理被池化对象的产生,激活,挂起,检验和销毁。

2.      ObjectPool(KeyedObjectPool):用于管理要被池化的对象的接触和归还,并通过PoolableObjectFactory完成相应的操作。

3.      ObjectPoolFactory(KeyedObjectPoolFactory):ObjectPool的工厂,里边有createPool()方法,用于大量生成相同类型和设置的池。

1.下载相关jar包以及文档

下载API以及相关jar包,本文用到的是目前最新的1.6版本。
下载源码以及官方例子,可供参考。

2.编写测试例子,新建项目只需要导入commons-pool-1.6.jar一个就可以

1)实体对象BaseObject.java

public class BaseObject {

    //记录从池中取出次数
private int num;
private boolean active; public BaseObject(){
active = true;
System.out.println("new BaseObject!!!!!");
}
//省略get set

2)管理池里对象的产生,激活,挂起,检验和销毁的工厂类

工厂类里的方法内部可以自己根据业务逻辑去写,例如:
makeObject()方法内部可以查询数据库封装成对象,注意一次只能创建一个池对象。
validateObject()方法内部可以自己验证该对象是否正在使用,比如可以通过对象的状态验证。
这是不带key的工厂类TestPoolableFactory.java
public class TestPoolableFactory implements PoolableObjectFactory {

    //重新初始化实例返回池
@Override
public void activateObject(Object arg0) throws Exception {
((BaseObject)arg0).setActive(true);
} //销毁被破坏的实例
@Override
public void destroyObject(Object arg0) throws Exception {
arg0 = null;
} //创建一个实例到对象池
@Override
public Object makeObject() throws Exception {
BaseObject bo = new BaseObject();
return bo;
} //取消初始化实例返回到空闲对象池
@Override
public void passivateObject(Object arg0) throws Exception {
((BaseObject)arg0).setActive(false);
} //验证该实例是否安全
@Override
public boolean validateObject(Object arg0) {
if(((BaseObject)arg0).isActive())
return true;
else
return false;
} }

这是带key的工厂类TestKeyPoolableFactory.java

public class TestKeyPoolableFactory implements KeyedPoolableObjectFactory<String, BaseObject> {

    //重新初始化实例返回池
@Override
public void activateObject(String arg0, BaseObject arg1) throws Exception {
((BaseObject)arg1).setActive(true);
} //销毁被破坏的实例
@Override
public void destroyObject(String arg0, BaseObject arg1) throws Exception {
arg1 = null;
} //创建一个实例到对象池
@Override
public BaseObject makeObject(String arg0) throws Exception {
//这里从数据库里查询出使用次数最少的配置
BaseObject bo = new BaseObject();
bo.setNum(0);
return bo;
} //取消初始化实例返回到空闲对象池
@Override
public void passivateObject(String arg0, BaseObject arg1) throws Exception {
((BaseObject)arg1).setActive(false);
} //验证该实例是否安全 true:正在使用
@Override
public boolean validateObject(String arg0, BaseObject arg1) {
//这里可以判断实例状态是否可用
if(((BaseObject)arg1).isActive())
return true;
else
return false;
}
}

3)测试main方法

不带key的main方法类PoolTest.java

public class PoolTest {

    public static void main(String[] args) {
BaseObject bo = null;
PoolableObjectFactory factory = new TestPoolableFactory();
GenericObjectPool pool = new GenericObjectPool(factory);
//这里两种池都可以,区别下文会提到
//ObjectPool pool = new StackObjectPool(factory);
try {
for(int i = 0; i < 5; i++) {
System.out.println("\n==========="+i+"===========");
System.out.println("池中处于闲置状态的实例pool.getNumIdle():"+pool.getNumIdle());
//从池里取一个对象,新创建makeObject或将以前闲置的对象取出来
bo = (BaseObject)pool.borrowObject();
System.out.println("bo:"+bo);
System.out.println("池中所有在用实例数量pool.getNumActive():"+pool.getNumActive());
if((i%2) == 0) {
//用完之后归还对象
pool.returnObject(bo);
System.out.println("归还对象!!!!");
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(bo != null) {
pool.returnObject(bo);
}
//关闭池
pool.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

输出结果:

===========0===========
池中处于闲置状态的实例pool.getNumIdle():0
new BaseObject!!!!!
bo:common.keypool.BaseObject@1fdc96c
池中所有在用实例数量pool.getNumActive():1
归还对象!!!! ===========1===========
池中处于闲置状态的实例pool.getNumIdle():1
bo:common.keypool.BaseObject@1fdc96c
池中所有在用实例数量pool.getNumActive():1 ===========2===========
池中处于闲置状态的实例pool.getNumIdle():0
new BaseObject!!!!!
bo:common.keypool.BaseObject@124bbbf
池中所有在用实例数量pool.getNumActive():2
归还对象!!!! ===========3===========
池中处于闲置状态的实例pool.getNumIdle():1
bo:common.keypool.BaseObject@124bbbf
池中所有在用实例数量pool.getNumActive():2 ===========4===========
池中处于闲置状态的实例pool.getNumIdle():0
new BaseObject!!!!!
bo:common.keypool.BaseObject@a20892
池中所有在用实例数量pool.getNumActive():3
归还对象!!!!

这里的池声明用ObjectPool或者GenericObjectPool的区别在于:

ObjectPool这种对象池的特点是:

  • 可以为对象池指定一个初始的参考大小(当空间不够时会自动增长)。
  • 在对象池已空的时候,调用它的borrowObject方法,会自动返回新创建的实例。
  • 可以为对象池指定一个可保存的对象数目的上限。达到这个上限之后,再向池里送回的对象会被自动送去回收。

GenericObjectPool这种对象池的特色是:

  • 可以设定最多能从池中借出多少个对象。
  • 可以设定池中最多能保存多少个对象。
  • 可以设定在池中已无对象可借的情况下,调用它的borrowObject方法时的行为,是等待、创建新的实例还是抛出异常。
  • 可以分别设定对象借出和还回时,是否进行有效性检查。
  • 可以设定是否使用一个单独的线程,对池内对象进行后台清理。
  • ……

这些参数可以通过一个Config类来管理,然后通过GenericObjectPool的setConfig(Config conf)方法来设置自定义的Config类。下面附上setConfig方法源码,就知道Config类需要哪些参数了:

源码GenericKeyedObjectPool.java类内部的setConfig方法

/**
* Sets the configuration.
* @param conf the new configuration to use.
* @see GenericKeyedObjectPool.Config
*/
public synchronized void setConfig(GenericKeyedObjectPool.Config conf) {
setMaxIdle(conf.maxIdle);
setMaxActive(conf.maxActive);
setMaxTotal(conf.maxTotal);
setMinIdle(conf.minIdle);
setMaxWait(conf.maxWait);
setWhenExhaustedAction(conf.whenExhaustedAction);
setTestOnBorrow(conf.testOnBorrow);
setTestOnReturn(conf.testOnReturn);
setTestWhileIdle(conf.testWhileIdle);
setNumTestsPerEvictionRun(conf.numTestsPerEvictionRun);
setMinEvictableIdleTimeMillis(conf.minEvictableIdleTimeMillis);
setTimeBetweenEvictionRunsMillis(conf.timeBetweenEvictionRunsMillis);
}

源码GenericObjectPool.java类内部的setConfig方法

/**
* Sets my configuration.
*
* @param conf configuration to use.
* @see GenericObjectPool.Config
*/
public void setConfig(GenericObjectPool.Config conf) {
synchronized (this) {
setMaxIdle(conf.maxIdle);
setMinIdle(conf.minIdle);
setMaxActive(conf.maxActive);
setMaxWait(conf.maxWait);
setWhenExhaustedAction(conf.whenExhaustedAction);
setTestOnBorrow(conf.testOnBorrow);
setTestOnReturn(conf.testOnReturn);
setTestWhileIdle(conf.testWhileIdle);
setNumTestsPerEvictionRun(conf.numTestsPerEvictionRun);
setMinEvictableIdleTimeMillis(conf.minEvictableIdleTimeMillis);
setTimeBetweenEvictionRunsMillis(conf.timeBetweenEvictionRunsMillis);
setSoftMinEvictableIdleTimeMillis(conf.softMinEvictableIdleTimeMillis);
setLifo(conf.lifo);
}
allocate();
}

1.      参数maxActive指明能从池中借出的对象的最大数目。如果这个值不是正数,表示没有限制。

2.      参数whenExhaustedA ction指定在池中借出对象的数目已达极限的情况下,调用它的borrowObject方法时的行为。可以选用的值有:

  • GenericObjectPool.WHEN_EXHAUSTED_BLOCK,表示等待;
  • GenericObjectPool.WHEN_EXHAUSTED_GROW,表示创建新的实例(不过这就使maxActive参数失去了意义);
  • GenericObjectPool.WHEN_EXHAUSTED_FAIL,表示抛出一个java.util.NoSuchElementException异常。

3.      参数maxWait指明若在对象池空时调用borrowObject方法的行为被设定成等待,最多等待多少毫秒。如果等待时间超过了这个数值,则会抛出一个java.util.NoSuchElementException异常。如果这个值不是正数,表示无限期等待。

4.      参数testOnBorrow设定在借出对象时是否进行有效性检查。

5.      参数testOnBorrow设定在还回对象时是否进行有效性检查。

6.      参数timeBetweenEvictionRunsMillis,设定间隔每过多少毫秒进行一次后台对象清理的行动。如果这个值不是正数,则实际上不会进行后台对象清理。

7.      参数minEvictableIdleTimeMillis,设定在进行后台对象清理时,视休眠时间超过了多少毫秒的对象为过期。过期的对象将被回收。如果这个值不是正数,那么对休眠时间没有特别的约束。

8.      参数testWhileIdle,则设定在进行后台对象清理时,是否还对没有过期的池内对象进行有效性检查。不能通过有效性检查的对象也将被回收。

9.      参数lifo,池对象的放入和取出默认是后进先出的原则,默认是true,代表后进后出,设置为false代表先进先出。

带key的main方法类KeyPoolTest.java

public class KeyPoolTest {

    public static void main(String[] args) {

        BaseObject bo = null;
BaseObject bo1 = null;
BaseObject bo2 = null; KeyedPoolableObjectFactory<String, BaseObject> keyFactory = new TestKeyPoolableFactory();
GenericKeyedObjectPool<String, BaseObject> keyPool = new GenericKeyedObjectPool<String, BaseObject>(keyFactory);
//keyPool.setLifo(false);
try {
//这里添加池对象,只需要传入key就会默认调用makeObject()方法创建一个对象
keyPool.addObject("一级");
keyPool.addObject("二级");
//这里注释掉,不初始创建这个键的池对象
//keyPool.addObject("三级");
System.out.println("池中处于闲置状态的实例pool.getNumIdle():"+keyPool.getNumIdle());
for (int i = 0; i < 5; i++) {
//从池里取对象
bo = keyPool.borrowObject("一级");
bo.setNum(bo.getNum()+1);
System.out.println("一级"+i+"-------"+bo+"-------"+bo.getNum()); bo1 = keyPool.borrowObject("二级");
bo1.setNum(bo1.getNum()+1);
System.out.println("二级"+i+"-------"+bo1+"-------"+bo1.getNum());
//上边注释掉的那行代码,这里取对象的时候如果没有闲置对象,也会默认去创建一个key="三级"的池对象
bo2 = keyPool.borrowObject("三级");
bo2.setNum(bo2.getNum()+1);
System.out.println("三级"+i+"-------"+bo2+"-------"+bo2.getNum()); if(i<3) {
//用完之后归还对象
keyPool.returnObject("一级", bo);
keyPool.returnObject("二级", bo1);
keyPool.returnObject("三级", bo2);
System.out.println("归还对象!!!");
}
}
//当前池里的实例数量
System.out.println("池中所有在用实例pool.getNumActive():"+keyPool.getNumActive());
//当前池里的处于闲置状态的实例
System.out.println("池中处于闲置状态的实例pool.getNumIdle():"+keyPool.getNumIdle());
} catch (Exception e) {
e.printStackTrace();
}
//这里就不写finally了,偷懒了,这里应该关闭池的
}
}

输出结果:

new BaseObject!!!!!
new BaseObject!!!!!
池中处于闲置状态的实例pool.getNumIdle():2
一级0-------common.keypool.BaseObject@158b649-------1
二级0-------common.keypool.BaseObject@127734f-------1
new BaseObject!!!!!
三级0-------common.keypool.BaseObject@1037c71-------1
归还对象!!!
一级1-------common.keypool.BaseObject@158b649-------2
二级1-------common.keypool.BaseObject@127734f-------2
三级1-------common.keypool.BaseObject@1037c71-------2
归还对象!!!
一级2-------common.keypool.BaseObject@158b649-------3
二级2-------common.keypool.BaseObject@127734f-------3
三级2-------common.keypool.BaseObject@1037c71-------3
归还对象!!!
一级3-------common.keypool.BaseObject@158b649-------4
二级3-------common.keypool.BaseObject@127734f-------4
三级3-------common.keypool.BaseObject@1037c71-------4
new BaseObject!!!!!
一级4-------common.keypool.BaseObject@1df073d-------1
new BaseObject!!!!!
二级4-------common.keypool.BaseObject@1546e25-------1
new BaseObject!!!!!
三级4-------common.keypool.BaseObject@b66cc-------1
池中所有在用实例pool.getNumActive():6
池中处于闲置状态的实例pool.getNumIdle():0

通过输出结果可以看出:

1.对象取出之后可以对对象进行更改,再放回池里这个更改是保留的。

2.池对象的放入和取出默认是后进先出的原则,可以通过池pool的setLifo(boolean lifo)方法设置,默认是true,代表后进先出,设置为false代表先进先出。如果为了池对象使用均衡,推荐使用false。

Apache Commons-pool实现对象池(包括带key对象池)的更多相关文章

  1. 对象池化技术 org.apache.commons.pool

    恰当地使用对象池化技术,可以有效地减少对象生成和初始化时的消耗,提高系统的运行效率.Jakarta Commons Pool组件提供了一整套用于实现对象池化的框架,以及若干种各具特色的对象池实现,可以 ...

  2. JedisCluster中应用的Apache Commons Pool对象池技术

    对象池技术在服务器开发上应用广泛.在各种对象池的实现中,尤其以数据库的连接池最为明显,可以说是每个服务器必须实现的部分.   apache common pool 官方文档可以参考:https://c ...

  3. 池化 - Apache Commons Pool

    对于那些创建耗时较长,或者资源占用较多的对象,比如网络连接,线程之类的资源,通常使用池化来管理这些对象,从而达到提高性能的目的.比如数据库连接池(c3p0, dbcp), java的线程池 Execu ...

  4. Apache Commons Pool 故事一则

    Apache Commons Pool 故事一则 最近工作中遇到一个由于对commons-pool的使用不当而引发的问题,习得正确的使用姿势后,写下这个简单的故事,帮助理解Apache Commons ...

  5. Apache Commons Pool 故事一则 专题

    Apache Commons Pool 故事一则 最近工作中遇到一个由于对commons-pool的使用不当而引发的问题,习得正确的使用姿势后,写下这个简单的故事,帮助理解Apache Commons ...

  6. Tomcat 开发web项目报Illegal access: this web application instance has been stopped already. Could not load [org.apache.commons.pool.impl.CursorableLinkedList$Cursor]. 错误

    开发Java web项目,在tomcat运行后报如下错误: Illegal access: this web application instance has been stopped already ...

  7. NoClassDefFoundError: org/apache/commons/pool/impl/GenericObjectPool

    错误:Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/pool/impl ...

  8. Spring + Tomcat 启动报错java.lang.ClassNotFoundException: org.apache.commons.pool.impl.GenericObjectPool

    错误如下: -- ::,-[TS] INFO http-- org.springframework.beans.factory.support.DefaultListableBeanFactory - ...

  9. org/apache/commons/pool/impl/GenericObjectPool异常的解决办法

    org/apache/commons/pool/impl/GenericObjectPool异常的解决办法 webwork+spring+hibernate框架的集成, 一启动Tomcat服务器就出了 ...

随机推荐

  1. Codeforce Round #225 Div2

    这回的C- -,弄逆序,我以为要弄个正的和反的,没想到是等价的,弄两个还是正确的,结果我又没注意1和0只能指1个方向,结果弄了4个,取了4个的最小值就错了,自己作死没弄出来...,后面又玩去了...哎 ...

  2. how to use automapper in c#, from cf~

    [DataContract] public class GroupDto { [DataMember] public int id { get; set; } [DataMember] public ...

  3. bzoj2743 [HEOI2012]采花

    做法是每个询问先算出询问区间中花的种类减去区间中只有一朵花的花的种类,这两个子问题都不算难,具体看代码吧.询问可以离线处理,用树状数组维护,复杂度O(nlogn). 不知道是想的复杂了还是打的太low ...

  4. 一个标准的ECharts代码

    <!DOCTYPE html> <head> <meta charset="utf-8"> <title>ECharts</t ...

  5. paper 79:MATLAB函数,interp1

    在matlab中有一个interp1()函数,可以帮助解决问题,具体情况如下:MATLAB中的插值函数为interp1,其调用格式为: yi= interp1(x,y,xi,'method') 其中x ...

  6. DDR(一)

    P-Bank:计算机早期的一个概念.目的:匹配内存芯片和CPU芯片的数据总线的宽度.方法:并联多个内存模块. L-Bank:对内部存储阵列的分割,避免寻址冲突,提高内存效率.通过ba信号选择bank, ...

  7. PAT乙级 1002. 写出这个数 (20)

    1002. 写出这个数 (20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 读入一个自然数n,计算其各位数字 ...

  8. 2. 星际争霸之php面向对象(二)

    题记==============================================================================本php设计模式专辑来源于博客(jymo ...

  9. zw版【转发·台湾nvp系列Delphi例程】HALCON color_fuses2

    zw版[转发·台湾nvp系列Delphi例程]HALCON color_fuses2 procedure TForm1.Button1Click(Sender: TObject);var w, h : ...

  10. SDK Manager failed to install 'java.exe' locking directory

    转自:http://stackoverflow.com/questions/13587478/sdk-manager-failed-to-install-java-exe-locking-direct ...