《java对象池化技术精品资料.docx》由会员分享,可在线阅读,更多相关《java对象池化技术精品资料.docx(38页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、使用Jakarta Commons Pool处理对象池化恰当地使用对象池化技术,可以有效地减少对象生成和初始化时的消耗,提高系统的运行效率。Jakarta Commons Pool组件提供了一整套用于实现对象池化的框架,以及若干种各具特色的对象池实现,可以有效地减少处理对象池化时的工作量,为其它重要的工作留下更多的精力和时间。创建新的对象并初始化的操作,可能会消耗很多的时间。在这种对象的初始化工作包含了一些费时的操作(例如,从一台位于20,000千米以外的主机上读出一些数据)的时候,尤其是这样。在需要大量生成这样的对象的时候,就可能会对性能造成一些不可忽略的影响。要缓解这个问题,除了选用更好的
2、硬件和更棒的虚拟机以外,适当地采用一些能够减少对象创建次数的编码技巧,也是一种有效的对策。对象池化技术(Object Pooling)就是这方面的著名技巧,而Jakarta Commons Pool组件则是处理对象池化的得力外援。对象池化技术对象池化的基本思路是:将用过的对象保存起来,等下一次需要这种对象的时候,再拿出来重复使用,从而在一定程度上减少频繁创建对象所造成的开销。用于充当保存对象的“容器”的对象,被称为“对象池”(Object Pool,或简称Pool)。 对于没有状态的对象(例如String),在重复使用之前,无需进行任何处理;对于有状态的对象(例如StringBuffer),在
3、重复使用之前,就需要把它们恢复到等同于刚刚生成时的状态。由于条件的限制,恢复某个对象的状态的操作不可能实现了的话,就得把这个对象抛弃,改用新创建的实例了。 并非所有对象都适合拿来池化因为维护对象池也要造成一定开销。对生成时开销不大的对象进行池化,反而可能会出现“维护对象池的开销”大于“生成新对象的开销”,从而使性能降低的情况。但是对于生成时开销可观的对象,池化技术就是提高性能的有效策略了。 Jakarta Commons Pool组件Jakarta Commons Pool是一个用于在Java程序中实现对象池化的组件。它的基本情况是: 主要作者:Morgan Delagrange、Geir M
4、agnusson、Craig McClanahan、Rodney Waldhoff、David Weinrich和Dirk Verbeeck 最新版本:1.1 所含包数:2个(mons.pool和mons.pool.impl) 所含类数:21个(其中有4个抽象类和6个接口) 适用平台:Java 2, Standard Edition. 单纯地使用Pool组件不需要太多的Java 2的知识和经验,对语法和基本概念(对象、异常、类、接口、实例、继承和实现等)有一般了解即可。 下载和安装为了顺利的按照本文中提到的方法使用Pool组件,除去Java 2 SDK外,还需要先准备下列一些东西: Jakar
5、ta Commons Pool o 所需版本:1.0.1+ o 下载地址: http:/jakarta.apache.org/commons/pool o 作用:处理对象池化 Jakarta Commons Collections o 所需版本:2.1+ o 下载地址: http:/jakarta.apache.org/commons/collections o 作用:支持Jakarta Commons Pool的运行 以上两种软件均有已编译包和源代码包两种形式可供选择。一般情况下,使用已编译包即可。不过建议同时也下载源代码包,作为参考资料使用。 如果打算使用源代码包自行编译,那么还需要准备以
6、下一些东西: Ant o 所需版本:1.5.3+ o 下载地址: http:/ant.apache.org o 作用:运行编译用脚本 JUnit o 所需版本:3.8.1+ o 下载地址: http:/www.junit.org o 作用:编译和运行单元测试 具体的编译方法,可以参看有关的Ant文档。 将解压或编译后得到的commons-pool.jar和commons-collections.jar放入CLASSPATH,就可以开始使用Pool组件了。 回页首PoolableObjectFactory、ObjectPool和ObjectPoolFactory在Pool组件中,对象池化的工作被
7、划分给了三类对象: PoolableObjectFactory用于管理被池化的对象的产生、激活、挂起、校验和销毁; ObjectPool用于管理要被池化的对象的借出和归还,并通知PoolableObjectFactory完成相应的工作; ObjectPoolFactory则用于大量生成相同类型和设置的ObjectPool。 相应地,使用Pool组件的过程,也大体可以划分成“创立PoolableObjectFactory”、“使用ObjectPool”和可选的“利用ObjectPoolFactory”三种动作。 创立PoolableObjectFactoryPool组件利用PoolableObj
8、ectFactory来照看被池化的对象。ObjectPool的实例在需要处理被池化的对象的产生、激活、挂起、校验和销毁工作时,就会调用跟它关联在一起的PoolableObjectFactory实例的相应方法来操作。 PoolableObjectFactory是在mons.pool包中定义的一个接口。实际使用的时候需要利用这个接口的一个具体实现。Pool组件本身没有包含任何一种PoolableObjectFactory实现,需要根据情况自行创立。 创立PoolableObjectFactory的大体步骤是: 1. 创建一个实现了PoolableObjectFactory接口的类。 import
9、mons.pool.PoolableObjectFactory; public class PoolableObjectFactorySample implements PoolableObjectFactory private static int counter = 0; 2. 为这个类添加一个Object makeObject()方法。这个方法用于在必要时产生新的对象。 public Object makeObject() throws Exception Object obj = String.valueOf(counter+); System.err.println(Making O
10、bject + obj); return obj; 3. 为这个类添加一个void activateObject(Object obj)方法。这个方法用于将对象“激活”设置为适合开始使用的状态。 public void activateObject(Object obj) throws Exception System.err.println(Activating Object + obj); 4. 为这个类添加一个void passivateObject(Object obj)方法。这个方法用于将对象“挂起”设置为适合开始休眠的状态。 public void passivateObject(
11、Object obj) throws Exception System.err.println(Passivating Object + obj); 5. 为这个类添加一个boolean validateObject(Object obj)方法。这个方法用于校验一个具体的对象是否仍然有效,已失效的对象会被自动交给destroyObject方法销毁 public boolean validateObject(Object obj) boolean result = (Math.random() 0.5); System.err.println(Validating Object + obj +
12、: + result); return result; 6. 为这个类添加一个void destroyObject(Object obj)方法。这个方法用于销毁被validateObject判定为已失效的对象。 public void destroyObject(Object obj) throws Exception System.err.println(Destroying Object + obj); 7.最后完成的PoolableObjectFactory类似这个样子: PoolableObjectFactorySample.java import mons.pool.Poolable
13、ObjectFactory; public class PoolableObjectFactorySample implements PoolableObjectFactory private static int counter = 0; public Object makeObject() throws Exception Object obj = String.valueOf(counter+); System.err.println(Making Object + obj); return obj; public void activateObject(Object obj) thro
14、ws Exception System.err.println(Activating Object + obj); public void passivateObject(Object obj) throws Exception System.err.println(Passivating Object + obj); public boolean validateObject(Object obj) /* 以1/2的概率将对象判定为失效 */ boolean result = (Math.random() 0.5); System.err.println(Validating Object
15、+ obj + : + result); return result; public void destroyObject(Object obj) throws Exception System.err.println(Destroying Object + obj); 回页首使用ObjectPool有了合适的PoolableObjectFactory之后,便可以开始请出ObjectPool来与之同台演出了。 ObjectPool是在mons.pool包中定义的一个接口,实际使用的时候也需要利用这个接口的一个具体实现。Pool组件本身包含了若干种现成的ObjectPool实现,可以直接利用。如
16、果都不合用,也可以根据情况自行创建。具体的创建方法,可以参看Pool组件的文档和源码。 ObjectPool的使用方法类似这样: 1. 生成一个要用的PoolableObjectFactory类的实例。 PoolableObjectFactory factory = new PoolableObjectFactorySample(); 2. 利用这个PoolableObjectFactory实例为参数,生成一个实现了ObjectPool接口的类(例如StackObjectPool)的实例,作为对象池。 ObjectPool pool = new StackObjectPool(factory)
17、; 3. 需要从对象池中取出对象时,调用该对象池的Object borrowObject()方法。 Object obj = null; obj = pool.borrowObject(); 4. 需要将对象放回对象池中时,调用该对象池的void returnObject(Object obj)方法。 pool.returnObject(obj); 5. 当不再需要使用一个对象池时,调用该对象池的void close()方法,释放它所占据的资源。 pool.close(); 6.这些操作都可能会抛出异常,需要另外处理。 比较完整的使用ObjectPool的全过程,可以参考这段代码: Objec
18、tPoolSample.java import mons.pool.ObjectPool; import mons.pool.PoolableObjectFactory; import mons.pool.impl.StackObjectPool; public class ObjectPoolSample public static void main(String args) Object obj = null; PoolableObjectFactory factory = new PoolableObjectFactorySample(); ObjectPool pool = new
19、StackObjectPool(factory); try for(long i = 0; i 100 ; i+) System.out.println(= + i + =); obj = pool.borrowObject(); System.out.println(obj); pool.returnObject(obj); obj = null;/明确地设为null,作为对象已归还的标志 catch (Exception e) e.printStackTrace(); finally try if (obj != null) /避免将一个对象归还两次 pool.returnObject(o
20、bj); pool.close(); catch (Exception e) e.printStackTrace(); 另外,ObjectPool接口还定义了几个可以由具体的实现决定要不要支持的操作,包括: void clear() 清除所有当前在此对象池中休眠的对象。int getNumActive() 返回已经从此对象池中借出的对象的总数。int getNumIdle() 返回当前在此对象池中休眠的对象的数目。void setFactory(PoolableObjectFactory factory) 将当前对象池与参数中给定的PoolableObjectFactory相关联。如果在当前状
21、态下,无法完成这一操作,会有一个IllegalStateException异常抛出。 回页首利用ObjectPoolFactory有时候,要在多处生成类型和设置都相同的ObjectPool。如果在每个地方都重写一次调用相应构造方法的代码,不但比较麻烦,而且日后修改起来,也有所不便。这种时候,正是使用ObjectPoolFactory的时机。 ObjectPoolFactory是一个在mons.pool中定义的接口,它定义了一个称为ObjectPool createPool()方法,可以用于大量生产类型和设置都相同的ObjectPool。 Pool组件中,对每一个ObjectPool实现,都有一
22、个对应的ObjectPoolFactory实现。它们相互之间,有一一对应的参数相同的构造方法。使用的时候,只要先用想要的参数和想用的ObjectPoolFactory实例,构造出一个ObjectPoolFactory对象,然后在需要生成ObjectPool的地方,调用这个对象的createPool()方法就可以了。日后无论想要调整所用ObjectPool的参数还是类型,只需要修改这一处,就可以大功告成了。 将 使用ObjectPool一节中的例子,改为使用ObjectPoolFactory来生成所用的ObjectPool对象之后,基本就是这种形式: ObjectPoolFactorySampl
23、e.java import mons.pool.ObjectPool; import mons.pool.ObjectPoolFactory; import mons.pool.PoolableObjectFactory; import mons.pool.impl.StackObjectPoolFactory; public class ObjectPoolFactorySample public static void main(String args) Object obj = null; PoolableObjectFactory factory = new PoolableObjec
24、tFactorySample(); 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
25、) e.printStackTrace(); finally try if (obj != null) pool.returnObject(obj); pool.close(); catch (Exception e) e.printStackTrace(); 回页首借助BasePoolableObjectFactoryPoolableObjectFactory定义了许多方法,可以适应多种不同的情况。但是,在并没有什么特殊需要的时候,直接实现PoolableObjectFactory接口,就要编写若干的不进行任何操作,或是始终返回true的方法来让编译通过,比较繁琐。这种时候就可以借助Base
26、PoolableObjectFactory的威力,来简化编码的工作。 BasePoolableObjectFactory是mons.pool包中的一个抽象类。它实现了PoolableObjectFactory接口,并且为除了makeObject之外的方法提供了一个基本的实现activateObject、passivateObject和destroyObject不进行任何操作,而validateObject始终返回true。通过继承这个类,而不是直接实现PoolableObjectFactory接口,就可以免去编写一些只起到让编译通过的作用的代码的麻烦了。 这个例子展示了一个从BasePoola
27、bleObjectFactory扩展而来的PoolableObjectFactory: BasePoolableObjectFactorySample.java import mons.pool.BasePoolableObjectFactory; public class BasePoolableObjectFactorySample extends BasePoolableObjectFactory private int counter = 0; public Object makeObject() throws Exception return String.valueOf(count
28、er+); 回页首各式各样的ObjectPool可口可乐公司的软饮料有可口可乐、雪碧和芬达等品种,百事可乐公司的软饮料有百事可乐、七喜和美年达等类型,而Pool组件提供的ObjectPool实现则有StackObjectPool、SoftReferenceObjectPool和GenericObjectPool等种类。 不同类型的软饮料各有各自的特点,分别适应不同消费者的口味;而不同类型的ObjectPool也各有各自的特色,分别适应不同的情况。 回页首StackObjectPoolStackObjectPool利用一个java.util.Stack对象来保存对象池里的对象。这种对象池的特色是
29、: 可以为对象池指定一个初始的参考大小(当空间不够时会自动增长)。 在对象池已空的时候,调用它的borrowObject方法,会自动返回新创建的实例。 可以为对象池指定一个可保存的对象数目的上限。达到这个上限之后,再向池里送回的对象会被自动送去回收。 StackObjectPool的构造方法共有六个,其中: 最简单的一个是StackObjectPool(),一切采用默认的设置,也不指明要用的PoolableObjectFactory实例。 最复杂的一个则是StackObjectPool(PoolableObjectFactory factory, int max, int init)。其中:
30、o 参数factory指明要与之配合使用的PoolableObjectFactory实例; o 参数max设定可保存对象数目的上限; o 参数init则指明初始的参考大小。 剩余的四个构造方法则是最复杂的构造方法在某方面的简化版本,可以根据需要选用。它们是: o StackObjectPool(int max) o StackObjectPool(int max, int init) o StackObjectPool(PoolableObjectFactory factory) o StackObjectPool(PoolableObjectFactory factory, int max)
31、 用不带factory参数的构造方法构造的StackObjectPool实例,必须要在用它的setFactory(PoolableObjectFactory factory)方法与某一PoolableObjectFactory实例关联起来后才能正常使用。 这种对象池可以在没有Jakarta Commmons Collections组件支持的情况下正常运行。 回页首SoftReferenceObjectPoolSoftReferenceObjectPool利用一个java.util.ArrayList对象来保存对象池里的对象。不过它并不在对象池里直接保存对象本身,而是保存它们的“软引用”(Sof
32、t Reference)。这种对象池的特色是: 可以保存任意多个对象,不会有容量已满的情况发生。 在对象池已空的时候,调用它的borrowObject方法,会自动返回新创建的实例。 可以在初始化同时,在池内预先创建一定量的对象。 当内存不足的时候,池中的对象可以被Java虚拟机回收。 SoftReferenceObjectPool的构造方法共有三个,其中: 最简单的是SoftReferenceObjectPool(),不预先在池内创建对象,也不指明要用的PoolableObjectFactory实例。 最复杂的一个则是SoftReferenceObjectPool(PoolableObjectFactory factory, int initSize)。其中: o 参数factory指明要与之配合使用的PoolableObjectFactory实例 o 参数initSize则指明初始化时在池中创建多少个对象。 剩下的一个构造方法,则是最复杂的构造方法在某方面的简化版本,适合在大多数情况下使用。它是: o SoftReferenceObjectPool(PoolableObjectFactory factory) 用不带factory参数的构造方法构造的SoftReferenceObjectPool实例,也要在用它的setFactory(PoolableObjectFact