文章目录
  1. 1. 依赖
  2. 2. 主要对象
  3. 3. 实例
    1. 3.1. 创立PoolableObjectFactory
    2. 3.2. 使用ObjectPool
    3. 3.3. 利用ObjectPoolFactory
  4. 4. 多种ObjectPool
    1. 4.1. StackObjectPool
    2. 4.2. SoftReferenceObjectPool
    3. 4.3. GenericObjectPool
    4. 4.4. KeyedObjectPool
  5. 5. 参考

上一篇文章中我们自己实现了一个对象池,但是实际上Java中已经存在一些第三方类库来帮助我们创建和管理对象池。鉴于不要重复造轮子的观点,我们决定使用apache的common-pools来实现我们的对象池。

依赖

除了Jakarta Commons Pool包外,还需要引入Jakarta Commons Collections,这样才可以使用pool组件。

主要对象

在Pool组件中,对象池化的工作被划分给了三类对象:

  1. PoolableObjectFactory用于管理被池化的对象的产生、激活、挂起、校验和销毁;
  2. ObjectPool用于管理要被池化的对象的借出和归还,并通知PoolableObjectFactory完成相应的工作;
  3. ObjectPoolFactory则用于大量生成相同类型和设置的ObjectPool。

相应地,使用Pool组件的过程,也大体可以划分成“创立PoolableObjectFactory”、“使用ObjectPool”和可选的“利用ObjectPoolFactory”三种动作。

实例

创立PoolableObjectFactory

public class GeTuiWorkerPoolableObjectFactory implements PoolableObjectFactory {
    private static final Logger logger = LoggerFactory.getLogger(GeTuiWorker.class);

    @Override
    public Object makeObject() throws Exception {
        logger.info("make object");
        Worker worker = new GeTuiWorker();
        return worker;
    }

    @Override
    public void destroyObject(Object o) throws Exception {
        logger.info("destroy object");
    }

    @Override
    public boolean validateObject(Object o) {
        return true;
    }

    @Override
    public void activateObject(Object o) throws Exception {
    }

    @Override
    public void passivateObject(Object o) throws Exception {

    }
}

使用ObjectPool

public class GeTuiWorkerPool implements Pool {
    private static final Logger logger = LoggerFactory.getLogger(GeTuiWorkerPool.class);

    private int max_active = 20;
    private int max_wait = 20;
    private GenericObjectPool pool;

    public void setMax_active(int max_active) {
        this.max_active = max_active;
    }

    public void setMax_wait(int max_wait) {
        this.max_wait = max_wait;
    }

    public GeTuiWorkerPool() {
        pool = new GenericObjectPool(new GeTuiWorkerPoolableObjectFactory(), max_active,
                GenericObjectPool.WHEN_EXHAUSTED_BLOCK, max_wait, true, true);
    }

    @Override
    public Worker getWorker() throws Exception {
        logger.info("get worker");
        return (Worker) pool.borrowObject();
    }

    @Override
    public void releaseWorker(Worker worker) throws Exception {
        logger.info("release worker");
        pool.returnObject(worker);
    }
}

利用ObjectPoolFactory

有时候,要在多处生成类型和设置都相同的ObjectPool。如果在每个地方都重写一次调用相应构造方法的代码,不但比较麻烦,而且日后修改起来,也有所不便。这种时候,正是使用ObjectPoolFactory的时机。

ObjectPoolFactory是一个在org.apache.commons.pool中定义的接口,它定义了一个称为ObjectPool createPool()方法,可以用于大量生产类型和设置都相同的ObjectPool。

Pool组件中,对每一个ObjectPool实现,都有一个对应的ObjectPoolFactory实现。它们相互之间,有一一对应的参数相同的构造方法。使用的时候,只要先用想要的参数和想用的ObjectPoolFactory实例,构造出一个ObjectPoolFactory对象,然后在需要生成ObjectPool的地方,调用这个对象的createPool()方法就可以了。日后无论想要调整所用ObjectPool的参数还是类型,只需要修改这一处,就可以大功告成了。

由于我的项目中我暂时还未使用该接口,所以直接copy别人的代码:

public class ObjectPoolFactorySample {
    public static void main(String[] args) {
        Object obj = null;
        PoolableObjectFactory factory
                = new PoolableObjectFactorySample();
        ObjectPoolFactory poolFactory
                = new StackObjectPoolFactory(factory);
        ObjectPool pool = poolFactory.createPool();
        try {
            for(long i = 0; i < 100 ; i++) {
                System.out.println("== " + i + " ==");
                obj = pool.borrowObject();
                System.out.println(obj);
                pool.returnObject(obj);
            }
            obj = null;
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            try{
                if (obj != null) {
                    pool.returnObject(obj);
                }
                pool.close();
            }
            catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}

多种ObjectPool

Pool组件提供的ObjectPool实现则有StackObjectPool、SoftReferenceObjectPool和GenericObjectPool等种类。

StackObjectPool

StackObjectPool利用一个java.util.Stack对象来保存对象池里的对象。这种对象池的特色是:

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

SoftReferenceObjectPool

SoftReferenceObjectPool利用一个java.util.ArrayList对象来保存对象池里的对象。不过它并不在对象池里直接保存对象本身,而是保存它们的“软引用”(Soft Reference)。这种对象池的特色是:

  1. 可以保存任意多个对象,不会有容量已满的情况发生。
  2. 在对象池已空的时候,调用它的borrowObject方法,会自动返回新创建的实例。
  3. 可以在初始化同时,在池内预先创建一定量的对象。
    当内存不足的时候,池中的对象可以被Java虚拟机回收。

GenericObjectPool

GenericObjectPool利用一个org.apache.commons.collections.CursorableLinkedList对象来保存对象池里的对象。这种对象池的特色是:

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

KeyedObjectPool

可以通过为每一组参数相同的同类对象建立一个单独的对象池来解决这个问题。但是,如果使用普通的ObjectPool来实施这个计策的话,因为普通的PoolableObjectFactory只能生产出大批设置完全一致的对象,就需要为每一组参数相同的对象编写一个单独的PoolableObjectFactory,工作量相当可观。这种时候就适合调遣Pool组件中提供的一种“带键值的对象池”来展开工作了。

Pool组件采用实现了KeyedObjectPool接口的类,来充当带键值的对象池。相应的,这种对象池需要配合实现了KeyedPoolableObjectFactory接口的类和实现了KeyedObjectPoolFactory接口的类来使用(这三个接口都在org.apache.commons.pool包中定义):

参考

  1. 使用Jakarta Commons Pool处理对象池化
文章目录
  1. 1. 依赖
  2. 2. 主要对象
  3. 3. 实例
    1. 3.1. 创立PoolableObjectFactory
    2. 3.2. 使用ObjectPool
    3. 3.3. 利用ObjectPoolFactory
  4. 4. 多种ObjectPool
    1. 4.1. StackObjectPool
    2. 4.2. SoftReferenceObjectPool
    3. 4.3. GenericObjectPool
    4. 4.4. KeyedObjectPool
  5. 5. 参考