java 对象池技术

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

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

2、对象池

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

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

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

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

    // 构造函数,池化对象
    public PooledObject(Object objection) {        this.objection = objection;
    }    // 返回此对象中的对象
    public Object getObject() {        return objection;
    }    // 设置此对象的,对象
    public void setObject(Object 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、开源的对象池

上面的例子基本够用,但是commons-pool提供了一套很好用的对象池组件,使用也很简单。 org.apache.commons.pool.ObjectPool定义了一个简单的池化接口,有三个对应实现,与我们的 Vector 这个集合不同的是,commons-pool提供了多样的集合,包括先进先出(FIFO),后进先出(LIFO)

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

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

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

原文发布于微信公众号 - 技术与生活(technology_life)

原文发表时间:2016-12-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏androidBlog

归并排序 递归版和非递归版的实现(java)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gdutxiaoxu/article/details/...

29910
来自专栏于晓飞的专栏

Java 容器 接口

在开发中使用容器正常的流程是,首先根据需求确定使用何种容器模型,然后选择一个符合性能要求的容器实现类或者自己实现一个容器类。例如:

15720
来自专栏Java 源码分析

数据结构Stack

​ 在很多应用中,我们需要维护多个对象的集合,这种操作非常简单。我们可能想要向集合中 加入某个元素,去掉某个元素,以及遍历 集合中的元素并对他们执行某种操...

34160
来自专栏xx_Cc的学习总结专栏

iOS底层原理总结 - 探寻Runtime本质(二)

28020
来自专栏猿人谷

求子数组的最大和

分析:输入一个整形数组,数组里有正数也有负数,数组中一个或连续的多个正数,求所有子数组的和的最大值。 当我们加上一个正数时,和会增加;当我们加上一个负数时,和会...

203100
来自专栏技术小站

Python 基础 (-)

Python 单词是“大蟒蛇”的意思。但是龟叔不是喜欢蟒蛇才起这个名字,而是正在追剧:英国电视喜剧片《蒙提·派森的飞行马戏团》(Monty Python and...

2K40
来自专栏null的专栏

设计模式——类图以及类与类之间的关系

    设计模式在程序设计上有着很重要的作用,使用设计模式可以使得代码更容易被理解,使得代码更规范,真正实现工程化。 一、用UML表示一个类 ? 类图一般是三行...

37440
来自专栏琦小虾的Binary

map 学习(下)——C++ 中的 hash_map, unordered_map

map 学习(下)——C++ 中的 hash_map, unordered_map 接上篇《map 学习(一)——C++中 map 的使用》。 一、hash_m...

3.7K70
来自专栏从流域到海域

《笨办法学Python》 第5课手记

《笨办法学Python》 第5课手记 本节内容复习了前两节的内容,并且引入了格式化字符,这节课里的格式化字符与C语言格式化字符,规则没有什么区别。 我把原文代码...

27790
来自专栏磐创AI技术团队的专栏

Python开发的十个Tips,你知道几个?

下面是十个Python中很有用的贴士和技巧。其中一些是初学这门语言常常会犯的错误。

10220

扫码关注云+社区

领取腾讯云代金券