zoukankan      html  css  js  c++  java
  • Java中的对象池模式

    Java中的对象池模式

    Java对象的生命周期分析:

    Java对象的生命周期大致包括三个阶段:

    对象的创建,对象的使用, 对象的清除。 因此,对象的生命周期长度可用如下的表达式表示: T = T1 + T2 + T3.其中T1表示对象的创建时间,T2表示对象的使用时间,而T3则表示对象的清除时间。由此,我们可以看出,只有T2是真正有效的时间,而T1,T3则是对象本身的开销。下面再看看T1, T3在对象的整个生命周期中所占的比例。

    我们知道,Java对象是通过构造函数来创建的,在这一过程中,该构造函数链中的所有构造函数也都会被自动调用。另外,默认情况下,调用类的构造函数时,Java会把变量初始化成确定的值:所有的对像被设置成null,整数变量(byte, short, int , long)设置成0,float和double变量设置成0.0,逻辑值设置成false,所以用new关键字来新建一个对象的时间开销是很大的,如表1所示。

    表1 一些操作所消耗的时间的对照表

    运算操作

    示例

    标准化时间

    本地赋值

    i = n

    1.0

    实例赋值

    this.i = n

    1.2

    方法调用

    Funct()

    5.9

    新建对象

    New Object()

    980

    新建数组

    New int[10]

    3100

     

    从表一可以看出,新建一个对象需要的980个单位的时间,是本地赋值时间的980倍,是方法调用时间的166倍,而若新建一个数组所花费的时间就更多了。

    再看清除对象的过程。我们知道,Java语言的一个优势,就是Java程序员不需要像C/C++程序员那样,显式地释放对象,而由称为垃圾收集器(Garbage Colletor)的自动内存管理系统,定时或内存凸显不足时,自动回收垃圾对象所占的内存。凡事有利总也有弊,这虽然为Java程序员设计者提供了极大的方便,但同时它也带来了较大的性能开销。这种开销包括两方面:首先是对象管理的开销,GC为了能够正确释放对象,它必须监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等。其次,在GC开始回收”垃圾”对象时,系统会暂停应用程序的执行,而独占CPU.因此,如果要改善应用程序的性能,一方面应尽量减少创建对象的次数;同时,还应尽量减少T1,T3的时间。而这些均可以通过对象池技术来实现。

    对象池技术的基本原理: 对象池技术基本原理的核心有两点:缓存和共享,即对于那些被频繁使用的对象,在使用完后,不立即将它们释放,而是将它们缓存起来,以供后续的应用程序重复使用,从而减少创建对象和释放对象的次数,进而改善应用程序的性能。事实上,由于对象池技术将对象限制在一定的数量,也有效地减少了应用程序在内存上的开销。

    实现一个对象池,一般会涉及到如下的类:

    ⑴对象池工厂(ObjectPoolFactory)类

    该类主要用于管理相同类型和设置的对象池(ObjectPool),它一般包含如下两个方法:createPool:用于创建特定类型和设置的对象池;destroyPool:用于释放指定的对象池;

    同时为了保证ObjectPoolFactory的单一实例,可以采用Singleton设计模式,见下述getInstance方法的实现:

    public synchronized ObjectPoolFactory getInstance() {

         if (poolFactory == null) {

             poolFactory = new ObjectPoolFactory();

             return poolFactory;

    }

    }

    ⑵参数对象(ParameterObject)类

           该类主要用于封装所创建对象池的一些属性参数,如池中可存放对象的数目的最大值(maxCount)、最小值(minCount)等。

    对象池(ObjectPool)类

    用于管理要被池化对象的借出和归还,并通知PoolableObjectFactory完成相应的工作。它一般包含如下两个方法:

    ◆   getObject: 用于从池中借出对象;

    ◆   returnObject:将池化对象返回到池中,并通知所有处于等待状态的线程;

    ◆   池化对象工厂(PoolableObjectFactory)类

    该类主要负责管理池化对象的生命周期,就简单来说,一般包含对象的创建的创建和销毁。该类同ObjectPoolFactory一样,也可将其实现为单实例。

    通用对象池的实现:

    对象池的构造和治理可以按照多种方式实现。最灵活的方式是将池化对象的Class类型在对象池之外指定,即在ObjectPoolFactory类创建对象池时,动态指定该对象池所池化对象的Class类型,其实现代码如下:

    public ObjectPool createPool(ParameterObject paraObj, Class clsType) {

                 return new ObjectPool(paraObj, clsType);

    }

    其中,paraObj参数用于指定对象池对的特征属性,clsType参数则指定了该对象池所存放对象的类型。对象池(ObjectPool)创建以后,下面就是利用它来治理对象了,具体实现如下;

    public class ObjectPool {

            private ParameteObject paraObj; //该对象池的属性参数对象

            private Class clsType; //该对象池中所存放对象得到类型

            private int currentNum = 0; //该对象池当前已创建的对象数目

            private Object currentObj; //该对象池当前可以

    }

    package com.test;

     

    public class ObjectPoolFactory {

       

        /**

         * 饿汉式单例类

         */

        private static final ObjectPoolFactory factory = new ObjectPoolFactory();

       

        /**

         * 私有默认的构造子

         */

        private ObjectPoolFactory() {

          

        }

       

        /**

         * 静态工厂方法

        * @return  池工厂

         */

        public static ObjectPoolFactory getInstance() {

           return factory;

        }

       

        /**

         *

         * @param paraObj  对象池参数对象

         * @param clsType   所创建对象类型

         * @return   对象池

         */

        public ObjectPool createPool(ParameterObject paraObj, Class clsType) {

           return new ObjectPool(paraObj, clsType);

        }

     

    }

    package com.test;

     

    import java.util.Vector;

     

    public class ObjectPool {

     

        private ParameterObject paraObj// 该对象池的属性参数对象

     

        private Class clsType// 该对象池中所存放对象的类型

     

        private int currentNum = 0; // 该对象池当前已创建的对象数目

     

        private Object currentObj// 该对象池当前可以借出的对象

     

        private Vector pool// 用于存放对象的池

     

        public ObjectPool(ParameterObject paraObj, Class clsType) {

           this.paraObj = paraObj;

           this.clsType = clsType;

           pool = new Vector();

        }

     

        public Object getObject() {

           if (pool.size() <= paraObj.getMinCount()) {

               if (currentNum <= paraObj.getMaxCount()) { // 如果当前池中无对象可用,

                                                     // 而且已创建的对象数目小于所限制的最大值,

                                                     // 就利用PoolObjectFactory创建一个新的对象

                  PoolableObjectFactory objFactory = PoolableObjectFactory

                         .getInstance();

                  currentObj = objFactory.createObject(clsType);

                  currentNum++;

               } else {

                  // 如果当前池中无对象可用,而且所创建的对象数目已达到所限制的最大值,

                  // 就只能等待其它线程返回对象到池中

                  synchronized (this) {

                      try {

                         wait();

                      } catch (InterruptedException e) {

                         System.out.println(e.getMessage());

                         e.printStackTrace();

                      }

                      currentObj = pool.firstElement();

                  }

               }

           } else {

               // 如果当前池中有可用的对象,就直接从池中取出对象

               currentObj = pool.firstElement();

           }

           return currentObj;

        }

     

        public void returnObject(Object obj) { // 确保对象具有正确的类型

           if (clsType.isInstance(obj)) {

               pool.addElement(obj);

               synchronized (this) {

                  notifyAll();

               }

           } else {

     

           }

        }

     

    }

    package com.test;

     

    public class PoolableObjectFactory {

       

        private static PoolableObjectFactory factory;

       

        private PoolableObjectFactory() {

          

        }

       

        public static synchronized PoolableObjectFactory getInstance() {

           if (factory == null) {

           factory = new PoolableObjectFactory();

           }

           return factory;

        }

     

        public Object createObject(Class clsType) {

           Object obj = null;

           try {

               obj = clsType.newInstance();

           } catch (InstantiationException e) {

               e.printStackTrace();

           } catch (IllegalAccessException e) {

               e.printStackTrace();

           }

           return obj;

        }

       

    }

    package com.test;

     

    public class ParameterObject {

       

        private int MinCount;

       

        private int MaxCount;

       

        public ParameterObject(int MaxCount, int MinCount) {

           this.MaxCount = MaxCount;

           this.MinCount = MinCount;

        }

     

        public int getMinCount() {

           return MinCount;

        }

     

        public void setMinCount(int minCount) {

           MinCount = minCount;

        }

     

        public int getMaxCount() {

           return MaxCount;

        }

     

        public void setMaxCount(int maxCount) {

           MaxCount = maxCount;

        }

     

    }

    package com.test;

     

    public class TestPool {

       

        public static void main(String[] args) {

           ObjectPoolFactory poolFactory = ObjectPoolFactory.getInstance();

           ParameterObject paraObj = new ParameterObject(2,1);

           ObjectPool pool = poolFactory.createPool(paraObj, StringBuffer.class);

           StringBuffer buffer = (StringBuffer)pool.getObject();

           buffer.append("hello");

           System.out.println(buffer.toString());

          

        }

     

    }

     

     

    String中的对象池模式:我们知道得到String对象有两种办法:String str1=”hello”;String str2=new String(“hello”);那么这两种创建String对象的方法有什么差异吗?当然有差异,差异在于第一种方法在对象池中拿对象,第二种方法直接生成新的对象。在JDK5.0里面,Java虚拟机在启动的时候会实例化9个对象池,这9个对象池分别用来存储8种基本类型的包装类对象和String对象。当我们在程序中直接用双引号括起来一个字符串是,JVM就到String的对象池里面去找看是否有一个值相同的对象,如果有,就拿现成的对象,如果没有就在对象池里创建一个对象,并返回。所以我们发现下面的代码输出true: String str1=”hello” ;String str2=”hello”;

    System.out.println(str1==str2);这说明str1和str2指向同一个对象,因为它们都是在对象池中拿到的,而下面的代码输出为false;因为在任何情况下,只要你去new一个String对象那都是创建了新的对象。与此类似的,在JDK5.0里面8中基本类型的包装类也有这样的差异:Interger i1=5; 在对象池中拿到Integer i2=5;所以i1==i2 Integer i3= new Integer(5); //重新创建对象,所以i2 != i3对象池的存在是为了避免频繁的创建和销毁对象的而影响系统性能,那我们自己写的类是否也可以使用对象池呢?当然可以,考察下面的代码:

    package com.test;

     

    import java.util.HashSet;

     

    import java.util.Set;

     

    class Student {

       

        private int id;

       

        private String name;

       

        private static Set<Student> students = new HashSet<Student>();

     

        public Student(int id, String name) {

           this.id = id;

           this.name = name;

        }

       

        public static Student getInstance(int id, String name) {

          

           for (Student st : students) {

               if (id == st.id  && name.equals(st.name)) {

                  return st;

               }

           }

           Student temp = new Student(id, name);

           students.add(temp);

           return temp;

          

        }

       

    }

     

    public class Test4 {

        public static void main(String[] args) {

           Student st1 = Student.getInstance(0, "liyangbing");

           Student st2 = Student.getInstance(0, "liyangbing");

           System.out.println("s1 == s2 is " + (st1 == st2)); //对象st2是从对象池中取得,故str1 == str2

           Student st3 = new Student(0, "liyangbing");

           Student st4 = new Student(0, "liyangbing");

           System.out.println("st3 == st4 is " + (st3 == st4)); //对象st3st4都是创建的,st3 != st4

        }

    Java曾经号称是纯面向对象的语言,那么我们经常用的8中基本数据类型算不算对象呢?答案很肯定不算,那么java又怎能称得上是纯面向对像的语言呢?为此,SUN公司特意的推出了8中基本数据类型的包装类,这样java语言才算是称得上纯面向对象的语言,那么在JDK中就有9个对象池,8个基本类包装类对象和String类对象。请注意:在J2ME里面没有对象池的概念。

    结束语:

    恰当地使用对象池技术,能有效地改善应用程序的性能。目前,对象池技术已得到广泛的应用,如对于网络和数据库连接这类重量级的对象,一般都会采用对象池技术。但在使用对象池技术时也要注意如下问题:

    并非任何情况下都适合采用对象池技术,基本上,只在重复生成某种对象的操作成为影响性能的关键因素的时候,才适合采用对象池技术。而如果进行池化所带来的性能提高并不重要的话,还是不采用对象池技术为佳,以保持代码的简明。

    要根据具体情况正确选择对象池的实现方式。如果是创建一个公用的对象池技术实现包,或需要在程序中动态指定所池化对象的Class类型时,才选择通用对象池,而大部分情况下,采用专用对象池就可以了。

    public class ObjectPool {
     private ParameterObject paraObj;//该对象池的属性参数对象
     private int currentNum = 0; //该对象池当前已创建的对象数目
     private StringBuffer currentObj;//该对象池当前可以借出的对象
     private Vector pool;//用于存放对象的池
     public ObjectPool(ParameterObject paraObj) {
      this.paraObj = paraObj;
      pool = new Vector();
     }
     public StringBuffer getObject() {
      if (pool.size() <= paraObj.getMinCount()) {
       if (currentNum <= paraObj.getMaxCount()) {
        currentObj = new StringBuffer();
        currentNum++;
       } 
       . . . 
      }
      return currentObj;
     }
     public void returnObject(Object obj) {
      // 确保对象具有正确的类型
      if (StringBuffer.isInstance(obj)) {
       . . . 
      }
     }
  • 相关阅读:
    sencha touch学习心得之FormPanel
    从零开始学习Sencha Touch MVC应用之十九
    sencha touch中datepicker的汉化
    从零开始学习Sencha Touch MVC应用之十九
    从零开始学习Sencha Touch MVC应用之十八
    sencha touch中datepicker的汉化
    sencha touch学习心得之FormPanel
    常用内置模块(二)——logging模块
    包的介绍
    常用内置模块(一)——time、os、sys、random、shutil、pickle、json
  • 原文地址:https://www.cnblogs.com/daichangya/p/12959278.html
Copyright © 2011-2022 走看看