1 / 15
文档名称:

对象池技术概述.docx

格式:docx   大小:370KB   页数:15页
下载后只包含 1 个 DOCX 格式的文档,没有任何的图纸或源代码,查看文件列表

如果您已付费下载过本站文档,您可以点这里二次下载

分享

预览

对象池技术概述.docx

上传人:碎碎念的折木 2023/2/7 文件大小:370 KB

下载得到文件列表

对象池技术概述.docx

相关文档

文档介绍

文档介绍:该【对象池技术概述 】是由【碎碎念的折木】上传分享,文档一共【15】页,该文档可以免费在线阅读,需要了解更多关于【对象池技术概述 】的内容,可以使用淘豆网的站内搜索功能,选择自己适合的文档,以下文字是截取该文章内的部分文字,如需要获得完整电子版,请下载此文档到您的设备,方便您编辑和打印。Apache的commons-pool供给了编写对象池的API,将用完的对象返回对象池中以便于下次利用,从而削减了对象创立时间。这对于创立对象相对耗时的应用来说,能够提高应用的性能。
commons-dbcp数据库连接池正是使用commons-pool来创立和数据库之间的连接对象,在对象池中保存这些对象,从而削减了频繁建立连接对象所造成的性能损耗。本文表达了commons-dbcp是怎样利用commons-pool来建立对象池的。
例如在tomcat中,,假设使用dbcp连接池,。我们可以从这个称为“数据源”的类中调用getConnection方法来获得与数据库的连接。但内部是如何实现的呢?对象池在其中占据什么位置呢?这一切对于外部使用者来说是透亮的。
BasicDataSource的getConnection首先建立了PoolingDataSource对象来getConnection。这个PoolingDataSource对象中引用了ObjectPool,在getConnection时,是从ObjectPool中借用了一个对象,。而对于生疏commons-pool的程序员来说,ObjectPool确定有与之对应的Factory创立对象,并放到池中。。然而PoolableConnectionFactory持有对ConnectionFactory的引用,ConnectionFactory可以有3种策略来创立Connection对象。其中DriverConnectionFactory调用了数据库厂商供给的Driver来获得Connection。
最近在做一个内部测试工具类的优化工作中接触到了连接池,对象池技术,,事实证明,经过两次改造,原来一个比较大的测试类需要500多秒,第一次优化后只需要300多秒,.
对象池就是以“空间换时间“的一种常用缓存机制,这里的“时间“特指创立时间,因此这也给出了对象池的适用范围:假设一种对象的创立过程格外耗时的话,,就是将创立的对象放到一个容器中,用完之后不是销毁而是再放回该容器,让其他的对象调用,对象池中还涉及到一些高级的技术,比方过期销毁,被破坏时销毁,对象数超过池大小销毁,对象池中没有可用空闲对象时等待等等.
apache的common-,这里先理解几个概念:
对象池(ObjectPool接口):可以把它认为是一种容器,它是用来装池对象的,并且包含了用来创立池对象的工厂对象
池对象:就是要放到池容器中的对象,理论上可以是任何对象.
对象池工厂(ObjectPoolFactory接口):用来创立对象池的工厂,这个没什么好说的.
池对象工厂(PoolableObjectFactory接口):用来创立池对象,将不用的池对象进展钝化(passivateObject),对要使用的池对象进展激活(activeObject),对池对象进展验证(validateObject),对有问题的池对象进展销毁(destroyObject)等工作
对象池中封装了创立,猎取,归还,销毁池对象的职责,固然这些工作都是通过池对象工厂来实施的,,存放时间,访问等待时间,空闲时间等等进展一些掌握,由于可以依据需要来调整这些设置.
当需要拿一个池对象的时候,就沉着器中取出一个,假设容器中没有的话,而且又没有到达容器的最大限制,那么就调用池对象工厂,建一个池对象,并调用工厂的激活方法,对创立的对象进展激活,,而对象池中又经没有空闲的对象,那么将会连续等待,直到有的空闲的对象被丢进来,固然这个等待也是有限度的,假设超出了这个限度,对象池就会抛出特别.
“出来混,总是要还的“,池对象也是如此,当将用完的池对象归还到对象池中的时候,对象池会调用池对象工厂对该池对象进展验证,假设验证不通过则被认为是有问题的对象,将会被销毁,同样假设容器已经满了,这个归还池对象将变的“无家可归“,也会被销毁,假设不属于上面两种状况,,激活,检查,钝化处理都不是必需的,因此我们在实现PoolableObjectFactory接口的时候,一般不作处理,给空实现即可,所以诞生了BasePoolableObjectFactory.
固然你也可以将要已有的对象创立好,然后通过addObject放到对象池中去,以备后用.
为了确保对对象池的访问都是线程安全的,全部对容器的操作都必需放在
synchronized
在apache的common-pool工具库中有5种对象池:GenericObjectPool和GenericKeyedObjectPool,SoftReferenceObjectPool,StackObjectPool,StackKeyedObjectPool.
五种对象池可分为两类,一类是无key的:
另一类是有key的:
前面两种用CursorableLinkedList来做容器,SoftReferenceObjectPool用ArrayList做容器,一次性创立全部池化对象,并对容器中的对象进展了软引用(SoftReference)处理,从而保证在内存充分的时候池对象不会轻易被jvm垃圾回收,,带key的相对简单一些,它会将池对象依据key来进展分类,具有一样的key被划分到一组类别中,因此有多少个key,,是由于一般的对象池通过makeObject方法创立的对象根本上都是一模一样的,,Stack遵循“后进先出“的原则并能保证线程安全,CursorableLinkedList是一个内部用游标(cursor)来定位当前元素的双向链表,是非线程安全的,,便利便利的容器.
使用对象池的一般步骤:创立一个池对象工厂,将该工厂注入到对象池中,当要取池对象,调用borrowObject,当要归还池对象时,调用returnObject,销毁池对象调用clear,假设要连池对象工厂也一起销毁,则调用close.
下面是一些时序图:
borrowObject:
returnObject:
invalidateObject:
apache的连接池工具库common-dbcp是common--pool生疏之后,对common-,Statment对象包装成池对象PoolableConnection,,持有一个对对象池的引用,在关闭的时候,不进展真正的关闭处理,而是通过调用:
Java代码
(this);
Java代码
或:
(_key,this);
这样一句,将连接对象放回连接池中.
而对应的对象池前者承受的是ObjectPool,后者是KeyedObjectPool,由于一个数据库只对应一个连接,
在对连接池的治理上,common-dbcp主要承受两种对象:
一个是PoolingDriver,另一个是PoolingDataSource,二者的区分是PoolingDriver是一个更底层的操作类,它持有一个连接池映射列表,一般针对在一个jvm中要连接多个数据库,,即一个数据源对应一个连接池.
下面是common-dbcp的构造关系:
Java代码
下面是参考了common-dbcp的例子之后写的一个从连接池中猎取连接的工具类
1./**
*创立连接
3. *
4. ****@since2023-1-22下午02:58:35
5. */
publicclassConnectionUtils{
//一些common-dbcp内部定义的protocol
privatestaticfinalStringPOOL_DRIVER_KEY=“jdbc:apache:commons:dbcp:“;
privatestaticfinalStringPOLLING_DRIVER=““;
10.
11. /**
12. *取得池化驱动器
13. *
****@return
****@throwsClassNotFoundException
****@throwsSQLException
17. */
privatestaticPoolingDrivergetPoolDriverthrowsClassNotFoundException,
SQLException{
(POLLING_DRIVER);
return(PoolingDriver)(POOL_DRIVER_KEY);
22. }
23.
24. /**
25. *销毁全部连接
26. *
27. ****@throwsException
28. */
publicstaticvoiddestorythrowsException{
PoolingDriverdriver=getPoolDriver;
String[]names=;
for(Stringname:names){
(name).close;
34. }
35. }
36.
37. /**
38. *从连接池中猎取数据库连接
39. */
publicstaticConnectiongetConnection(TableMetaDatatable)
throwsException{
Stringkey=;43.
44. PoolingDriverdriver=getPoolDriver;45.
ObjectPoolpool=null;
//这里找不到连接池会抛特别,需要catch一下
try{
pool=(key);
}catch(Exceptione){
51. }
52.
if(pool==null){
//依据数据库类型构建连接工厂
ConnectionFactoryconnectionFactory=null;
if(!=null
&&==){
();
connectionFactory=newDriverManagerConnectionFactory(table
.getDBUrl,null);
}else{
();
connectionFactory=newDriverManagerConnectionFactory(table
.getDBUrl,,);
65. }
66.
//构造连接池
ObjectPoolconnectionPool=newGenericObjectPool(null);
newPoolableConnectionFactory(connectionFactory,connectionPool,
70.
null,null,false,true);
71.
72.
//将连接池注册到driver中
73.
(key,connectionPool);
74.
}
75.
//从连接池中拿一个连接
(POOL_DRIVER_KEY+key);
78. }
79.
80.}
Java对象的生命周期大致包括三个阶段:对象的创立,对象的使用,对象的去除。因此,对象的生命周期长度可
用如下的表达式表示:T=T1+T2+T3。其中T1表示对象的创立时间,T2表示对象的使用时间,而T3则表示其去除时间。由此,我们可以看出,只有T2是真正有效的时间,而T1、T3则是对象本身的开销。下面再看看T1、T3在对象的整个生命周期中所占的比例。
我们知道,Java对象是通过构造函数来创立的,在这一过程中,该构造函数链中的全部构造函数也都会被自
动调用。另外,默认状况下,调用类的构造函数时,Java会把变量初始化成确定的值:全部的对象被设置成null,整数变量(byte、short、int、long)设置成0,,规律值设置成false。所以用new关键字来建一个对象的时间开销是很大的,如表1所示。
表1一些操作所消耗时间的比照表运算操作例如标准化时间
本地赋值i=
=
[10]3100
从表1可以看出,建一个对象需要980个单位的时间,是本地赋值时间的980倍,是方法调用时间的166
倍,而假设建一个数组所花费的时间就更多了。
再看去除对象的过程。我们知道,Java语言的一个优势,就是Java程序员勿需再像C/C++程序员那样,显式地释放对象,而由称为垃圾收集器(GarbageCollector)的自动内存治理系统,定时或在内存凸现出缺乏时,自动回收垃圾对象所占的内存。凡事有利总也有弊,这虽然为Java程序设计者供给了极大的便利,但同时它也带来了较大的性能开销。这种开销包括两方面,首先是对象治理开销,GC为了能够正确释放对象,它必需监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等。其次,在GC开头回收“垃圾”对象时,系统
会暂停应用程序的执行,而单独占用CPU。
因此,假设要改善应用程序的性能,一方面应尽量削减创立对象的次数;同时,还应尽量削减T1、T3的时间,而这些均可以通过对象池技术来实现。
对象池技术的根本原理
对象池技术根本原理的核心有两点:缓存和共享,即对于那些被频繁使用的对象,在使用完后,不马上将它们释放,而是将它们缓存起来,以供后续的应用程序重复使用,从而削减创立对象和释放对象的次数,进而改善应用程序的性能。事实上,由于对象池技术将对象限制在肯定的数量,也有效地削减了应用程序内存上的开销。
实现一个对象池,一般会涉及到如下的类:
对象池工厂(ObjectPoolFactory)类
该类主要用于治理一样类型和设置的对象池(ObjectPool),它一般包含如下两个方法:
·createPool:用于创立特定类型和设置的对象池;
·destroyPool:用于释放指定的对象池;
同时为保证ObjectPoolFactory的单一实例,可以承受Singleton设计模式,见下述getInstance方法的实
现:
publicstaticObjectPoolFactorygetInstance{if(poolFactory==null){
poolFactory=newObjectPoolFactory;
}
returnpoolFactory;
}