搜索
您的当前位置:首页正文

java 对象池技术

来源:二三娱乐

中断了一段时间,再次开始技术之旅;心里有个小目标,先把对象池技术梳理清楚。


1、为什么用对象池

在 java 中,对象的生命周期包括对象创建、对象使用,对象消失三个时间段,其中对象的使用是对象真正需要存活的时间,不好修改,该用的时候还得使用啊。对象的创建和消失就得好好控制下了。对象的创建是比较费时间的,也许感觉不到,好比一个赋值操作int i=1,也是需要耗时的,在比如构造一个对象,一个数组就更加消耗时间。再说对象的消除,在 java 里面使用 GC 来进行对象回收,其实也是需要对对象监控每一个运行状态,包括引用,赋值等。在 Full GC 的时候,会暂停其他操作,独占 CPU。所以,我们需要控制对象的创建数量,也不要轻易的让对象消失,让他的复用更加充分。

2、对象池

对象池其实就是一个集合,里面包含了我们需要的对象集合,当然这些对象都被池化了,也就是被对象池所管理,想要这样的对象,从池子里取个就行,但是用完得归还。对象池的对象最好是创建比较费时的大对象,如果是太简单的对象,再进入池化的时间比自己构建还多,就不划算了。可以理解对象池为单例模式的延展,多例模式,就那么几个对象实例,再多没有了。

3、自定义一个低质量的对象池

首先构造一个池化对象,也就是对实际对象封装下,为什么呢?当然是为了让对象池更好的管理



public  class PooledObject<T> {

 private T objection = null;// 外界使用的对象
 private boolean busy = false; // 此对象是否正在使用的标志,默认没有正在使用

 // 构造函数,池化对象
 public PooledObject(T objection) {
  this.objection = objection;
 }

 // 返回此对象中的对象
 public T getObject() {
  return objection;
 }

 // 设置此对象的,对象
 public void setObject(T objection) {
  this.objection = objection;
 }

 // 获得对象对象是否忙
 public boolean isBusy() {
  return busy;
 }

 // 设置对象的对象正在忙
 public void setBusy(boolean busy) {
  this.busy = busy;
 }
 
 
}

池化对象现在包括两个属性,一个是原始对象的引用,另外一个表示当前对象是否在使用

接下来把对象池写出来


import java.util.Enumeration;
import java.util.Vector;

public abstract class ObjectPool<T> {
    public static int numObjects = 10; // 对象池的大小
    public static int maxObjects = 50; // 对象池最大的大小
    protected Vector<PooledObject<T>> objects = null; // 存放对象池中对象的向量(PooledObject类型)

    public ObjectPool() {
    }

    /*** 创建一个对象池 ***/
    public synchronized void createPool() {
        // 确保对象池没有创建。如果创建了,保存对象的向量 objects 不会为空
        if (objects != null) {
            return; // 如果己经创建,则返回
        }
        // 创建保存对象的向量 , 初始时有 0 个元素
         objects = new Vector<PooledObject<T>>();
         for (int i = 0; i < numObjects; i++) {
                objects.addElement(create());
            }
    }

    public abstract PooledObject<T> create();

    public synchronized T getObject() {
        // 确保对象池己被创建
        if (objects == null) {
            return null; // 对象池还没创建,则返回 null
        }
        T t = getFreeObject(); // 获得一个可用的对象
        // 如果目前没有可以使用的对象,即所有的对象都在使用中
        while (t == null) {
            wait(250);
            t = getFreeObject(); // 重新再试,直到获得可用的对象,如果
            // getFreeObject() 返回的为 null,则表明创建一批对象后也不可获得可用对象
        }
        return t;// 返回获得的可用的对象
    }

    /**
     * 本函数从对象池对象 objects 中返回一个可用的的对象,如果 当前没有可用的对象,则创建几个对象,并放入对象池中。
     * 如果创建后,所有的对象都在使用中,则返回 null
     */
    private T getFreeObject() {
        // 从对象池中获得一个可用的对象
        T obj = findFreeObject();
        if (obj == null) {
            createObjects(10); // 如果目前对象池中没有可用的对象,创建一些对象
            // 重新从池中查找是否有可用对象
            obj = findFreeObject();
            // 如果创建对象后仍获得不到可用的对象,则返回 null
            if (obj == null) {
                return null;
            }
        }
        return obj;
    }

    public void createObjects(int increment){
        for (int i = 0; i < increment; i++) {
            if (objects.size() > maxObjects) {
                return;
            }
            objects.addElement(create());
        }
    }

    /**
     * 查找对象池中所有的对象,查找一个可用的对象, 如果没有可用的对象,返回 null
     */
    private T findFreeObject() {
        T obj = null;
        PooledObject<T> pObj = null;
        // 获得对象池向量中所有的对象
        Enumeration<PooledObject<T>> enumerate = objects.elements();
        // 遍历所有的对象,看是否有可用的对象
        while (enumerate.hasMoreElements()) {
            pObj = (PooledObject<T>) enumerate.nextElement();

            // 如果此对象不忙,则获得它的对象并把它设为忙
            if (!pObj.isBusy()) {
                obj = pObj.getObject();
                pObj.setBusy(true);
            }
        }
        return obj;// 返回找到到的可用对象
    }

    /**
     * 此函数返回一个对象到对象池中,并把此对象置为空闲。 所有使用对象池获得的对象均应在不使用此对象时返回它。
     */

    public void returnObject(T obj) {
        // 确保对象池存在,如果对象没有创建(不存在),直接返回
        if (objects == null) {
            return;
        }
        PooledObject<T> pObj = null;
        Enumeration<PooledObject<T>> enumerate = objects.elements();
        // 遍历对象池中的所有对象,找到这个要返回的对象对象
        while (enumerate.hasMoreElements()) {
            pObj = (PooledObject<T>) enumerate.nextElement();
            // 先找到对象池中的要返回的对象对象
            if (obj == pObj.getObject()) {
                // 找到了 , 设置此对象为空闲状态
                pObj.setBusy(false);
                break;
            }
        }
    }

    /**
     * 关闭对象池中所有的对象,并清空对象池。
     */
    public synchronized void closeObjectPool() {
        // 确保对象池存在,如果不存在,返回
        if (objects == null) {
            return;
        }
        PooledObject<T> pObj = null;
        Enumeration<PooledObject<T>> enumerate = objects.elements();
        while (enumerate.hasMoreElements()) {
            pObj = (PooledObject<T>) enumerate.nextElement();
            // 如果忙,等 0.5 秒
            if (pObj.isBusy()) {
                wait(500); // 等
            }
            // 从对象池向量中删除它
            objects.removeElement(pObj);
        }
        // 置对象池为空
        objects = null;
    }

    /**
     * 使程序等待给定的毫秒数
     */
    private void wait(int mSeconds) {
        try {
            Thread.sleep(mSeconds);
        } catch (InterruptedException e) {
        }
    }
}

为了泛化处理,这个对象池是个抽象类,接下来具体实现一个

public class DefaultObjectPool extends ObjectPool<String> {

    @Override
    public PooledObject<String> create(){
        return new PooledObject<String>(new String(""+1));
    }

}

最后测试下:

    public static void main(String[] args) {
        ObjectPool<String> objPool = new DefaultObjectPool();
        objPool.createPool();
        String obj = objPool.getObject();
        objPool.returnObject(obj);
        objPool.closeObjectPool();
    }

4、开源的对象池

StackObjectPool :实现了后进先出(LIFO)行为。
SoftReferenceObjectPool: 实现了后进先出(LIFO)行为。另外,对象池还在SoftReference 中保存了每个对象引用,允许垃圾收集器针对内存需要回收对象。

KeyedObjectPool定义了一个以任意的key访问对象的接口(可以池化对种对象),有两种对应实现。
GenericKeyedObjectPool :实现了先进先出(FIFO)行为。
StackKeyedObjectPool : 实现了后进先出(LIFO)行为。

PoolableObjectFactory 定义了池化对象的生命周期方法,我们可以使用它分离被池化的不同对象和管理对象的创建,持久,销毁。
BasePoolableObjectFactory这个实现PoolableObjectFactory接口的一个抽象类,我们可用扩展它实现自己的池化工厂。

Top