对象池技术在服务器开发上应用广泛。在各种对象池的实现中,尤其以数据库的连接池最为明显,可以说是每个服务器必须实现的部分。本文是个人学习对象池的一个记录,以Apache的commons-pool实现为研究对象。在下一篇blog中,本人将继续研究Apache的common-dbcp,这是对象池技术在JDBC上的一个应用范例。
Apache对象池技术的实现上颇为简单,只有2个主要的对象:ObjectPool,用于管理对象池中所有的对象,以及对象的借出,和回收。PoolableObjectFactory,被ObjectPool生成,借出和回收的对象。之所以叫做Factory,只是是因为它导出了几个负责生命期管理的函数:makeObject,destoryObject,activeObject...。
ObjectPool维护一个列表,其中存放所有已经生成的对象。同时导出几个方法,如borrowObject,returnObject,addObject等等。当用户调用borrowObject时,ObjectPool查看当前列表中的空闲对象的数目,如果有空闲的对象,则初始化该对象后返回给用户,否则创建一个对象,返回给用户使用。同理,当用户调用returnObject时,ObjectPool查看当前队列中的空闲对象数目,如果数目小于DEFAULT_MAX_SLEEPING,则将改对象的状态清空,然后放到队列中,作为备用对象;否则直接销毁改对象。
这种备用的观念正是对象池的理论基础,可以很大程度上减少对象生成和销毁的次数。对于那些初始化过程很慢的对象来说,减少对象构造和销毁的次数就等于大幅度提高了整体效率。特别是对于数据库连接这样的对象,由于进行JNDI搜索的效率极为低下,应用对象池技术是理所当然的。
Apache的commons-pool使用起来非常简单,首先需要创建一个你认为有必要池化的对象,实现PoolableObejctFactory的几个方法。然后构造一种ObjectPool。Apache默认提供了3种ObjectPool:StackObjectPool,GenericObjectPool,SoftReferenceObejctPool,一般使用StackObejctPool就可以了。然后当需要创建对象时,使用StackObejctPool.borrowObejct;使用完对象后,调用StackObjectPool.returnObject,就完成了对象池的操作。
需要注意的是,对象池技术并不是对任何对象都适用。因为对象池本身的操作要耗费一些资源,对于一些小对象来说,使用对象池可能取得相反的效果。IBM DeveloperWorks上有一篇论文,指出简单对象如Point,Size等,使用对象池技术并不能带来性能的该改善;而复杂对象如JPanel,JFrame等,使用对象池后能带来稍微的性能优势;最最适合对象池技术的是一些耗时操作,如JDBC连接,线程等。
如果需要编译commons-pool,一般需要修改build.xml文件,因为commons-pool使用了其它两个java library: commons-collection和junit。其中junit只是编译测试代码才需要,如果不想编译测试代码,则可以不管junit,使用ant build.jar命令编译即可。commons-pool库的位置需要修改一下,在build.xml文件中,
<property name="commons-collections.jar" value="${basedir}/commons-collections-3.1.jar"/>
将value改为你的commons-collection库的存放位置即可。编译出来的library在dist/下。
如果对ObjectPool有兴趣,可以参考Apache的具体文档,或者浏览DeveloperWorks上的几篇精彩论文。本人是java新手,如果错误,欢迎指正,也欢迎鄙视。