当前位置: 首页 > 工具软件 > Commons Pool > 使用案例 >

commons-pool2和commons-pool对象池使用

潘佐
2023-12-01

概念

  对象池(ObjectPool): 掌管对象的生命周期,获取,激活,验证,钝化,销毁等

  池对象(PooledObject): 被创建在池中的对象,自己可以有一些附加信息

  池对象工厂(PooledObjectFactory): 池中对象各个生命周期的具体实现,怎么创建,怎么验证,怎么销毁。

  对象池化主要用于减少对象在创建和销毁上面的开销,如果是小对象则不需要池化,如果是大对象可以考虑池化,对于像数据库连接、网络之类的重对象来说是很有必要池化的,开发者自己根据需求判断,如果创建某种对象成为了影响程序性能的关键因素则需要池化。

使用commons-pool2

1、maven引入:

<dependency>
       <groupId>org.apache.commons</groupId>
       <artifactId>commons-pool2</artifactId>
       <version>2.4.2</version>
 </dependency>

2、创建池对象工厂,继承BasePooledObjectFactory

import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

/**
 * JdbcUtils工具类对象池工厂
 */
public class JdbcUtilsPoolFactory extends BasePooledObjectFactory<JdbcUtils> {

    static GenericObjectPool<JdbcUtils> pool = null;

    // 取得对象池工厂实例
    public synchronized static GenericObjectPool<JdbcUtils> getInstance() {
        if (pool == null) {
            GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
            poolConfig.setMaxIdle(-1);
            poolConfig.setMaxTotal(-1);
            poolConfig.setMinIdle(100);
            poolConfig.setLifo(false);
            pool = new GenericObjectPool<JdbcUtils>(new JdbcUtilsPoolFactory(), poolConfig);
        }
        return pool;
    }

    public static JdbcUtils borrowObject() throws Exception{
        return (JdbcUtils) JdbcUtilsPoolFactory.getInstance().borrowObject();
    }

    public static void returnObject(JdbcUtils jdbcUtils) throws Exception{
        JdbcUtilsPoolFactory.getInstance().returnObject(jdbcUtils);
    }

    public static void close() throws Exception{
        JdbcUtilsPoolFactory.getInstance().close();
    }

    public static void clear() throws Exception{
        JdbcUtilsPoolFactory.getInstance().clear();
    }

    @Override
    public JdbcUtils create() throws Exception {
        return new JdbcUtils();
    }

    @Override
    public PooledObject<JdbcUtils> wrap(JdbcUtils obj) {
        return new DefaultPooledObject<JdbcUtils>(obj);
    }
}   

3、使用对象池

public static void main(String[] args) throws Exception {  
      JdbcUtils jdbcUtils = JdbcUtilsPoolFactory.borrowObject();
      jdbcUtils.domestring();
      JdbcUtilsPoolFactory.returnObject(jdbcUtils);
}  

使用commons-pool, 实现PoolableObjectFactory

1、对象BaseObject

public class BaseObject {
    //记录从池中取出次数  
    private int num;  
    private boolean active;  

    public BaseObject(){  
        active = true;  
        System.out.println("new BaseObject!!!!!");  
    }

    public int getNum() {
        return num;
    }
    public void setNum(int num) {
        this.num = num;
    }
    public boolean isActive() {
        return active;
    }
    public void setActive(boolean active) {
        this.active = active;
    }  
}

2、MyPoolableFactory对象池,实现PoolableObjectFactory

import org.apache.commons.pool.PoolableObjectFactory;

public class MyPoolableFactory 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;  
    }  
}

3、测试PoolableObjectFactory

import org.apache.commons.pool.PoolableObjectFactory;
import org.apache.commons.pool.impl.GenericObjectPool;

/*
 * 这里的池声明用ObjectPool或者GenericObjectPool的区别在于:
 * (1)ObjectPool :  
        GenericObjectPool这种对象池的特色是:
            可以设定最多能从池中借出多少个对象。
            可以设定池中最多能保存多少个对象。
            可以设定在池中已无对象可借的情况下,调用它的borrowObject方法时的行为,是等待、创建新的实例还是抛出异常。
            可以分别设定对象借出和还回时,是否进行有效性检查。
            可以设定是否使用一个单独的线程,对池内对象进行后台清理。
            ……
        StackObjectPool:使用LIFO行为实现的ObjectPool。
        SoftReferenceObjectPool:
            使用LIFO行为实现的ObjectPool。此外,在这个对象池实现中,每个对象都会被包装到一个SoftReference中。
            SoftReference允许垃圾回收机制在需要释放内存时回收对象池中的对象。


源码GenericObjectPool.java类内部的setConfig方法
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代表先进先出。
 */
public class PoolTest {
    public static void main(String[] args) {  
        BaseObject bo = null;  
        PoolableObjectFactory factory = new MyPoolableFactory();  
        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();  
            }  
        }  
    }  
}

使用commons-pool, 实现KeyedPoolableObjectFactory

1、创建对象BaseObject, 代码同上
2、创建MyKeyPoolableFactory, 实现KeyedPoolableObjectFactory

import org.apache.commons.pool.KeyedPoolableObjectFactory;

public class MyKeyPoolableFactory implements KeyedPoolableObjectFactory {

    //重新初始化实例返回池  
    @Override  
    public void activateObject(Object arg0, Object arg1) throws Exception {
        ((BaseObject)arg1).setActive(true);  
    }  

    //销毁被破坏的实例  
    @Override  
    public void destroyObject(Object arg0, Object arg1) throws Exception {
        arg1 = null;  
    }  

    //创建一个实例到对象池  
    @Override  
    public Object makeObject(Object arg0) throws Exception {
        //这里从数据库里查询出使用次数最少的配置  
        BaseObject bo = new BaseObject();  
        bo.setNum(0);  
        return bo;  
    }  

    //取消初始化实例返回到空闲对象池  
    @Override  
    public void passivateObject(Object arg0, Object arg1) throws Exception {
        ((BaseObject)arg1).setActive(false);  
    }  

    //验证该实例是否安全 true:正在使用  
    @Override  
    public boolean validateObject(Object arg0, Object arg1) {
        //这里可以判断实例状态是否可用  
        if(((BaseObject)arg1).isActive())  
            return true;  
        else  
            return false;  
    }
}

3、测试MyKeyPoolableFactory

import org.apache.commons.pool.KeyedPoolableObjectFactory;
import org.apache.commons.pool.impl.GenericKeyedObjectPool;

public class KeyPoolTest {
    public static void main(String[] args) {  

        BaseObject bo = null;  
        BaseObject bo1 = null;  
        BaseObject bo2 = null;  

        KeyedPoolableObjectFactory keyFactory = new MyKeyPoolableFactory();  
        GenericKeyedObjectPool keyPool = new GenericKeyedObjectPool(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 = (BaseObject) keyPool.borrowObject("一级");  
                bo.setNum(bo.getNum()+1);  
                System.out.println("一级"+i+"-------"+bo+"-------"+bo.getNum());  

                bo1 = (BaseObject) keyPool.borrowObject("二级");  
                bo1.setNum(bo1.getNum()+1);  
                System.out.println("二级"+i+"-------"+bo1+"-------"+bo1.getNum());  
                //上边注释掉的那行代码,这里取对象的时候如果没有闲置对象,也会默认去创建一个key="三级"的池对象  
                bo2 = (BaseObject) 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了,偷懒了,这里应该关闭池的  
    }  
}  
 类似资料: