摘 要 本文在分析對象池技術基本原理的基礎上給出了對象池技術的兩種實現方式還指出了使用對象池技術時所應注意的問題
關鍵詞 對象池對象池技術Java 對象性能
Java對象的生命周期分析
Java對象的生命周期大致包括三個階段對象的創建對象的使用對象的清除因此對象的生命周期長度可用如下的表達式表示T = T + T +T其中T表示對象的創建時間T表示對象的使用時間而T則表示其清除時間由此我們可以看出只有T是真正有效的時間而TT則是對象本身的開銷下面再看看TT在對象的整個生命周期中所占的比例
我們知道Java對象是通過構造函數來創建的在這一過程中該構造函數鏈中的所有構造函數也都會被自動調用另外默認情況下調用類的構造函數時Java會把變量初始化成確定的值所有的對象被設置成null整數變量(byteshortintlong)設置成float和double變量設置成邏輯值設置成false所以用new關鍵字來新建一個對象的時間開銷是很大的如表所示
表 一些操作所耗費時間的對照表
運算操作
示例
標准化時間
本地賦值
i = n
實例賦值
thisi = n
方法調用
Funct()
新建對象
New Object()
新建數組
New int[]
從表可以看出新建一個對象需要個單位的時間是本地賦值時間的倍是方法調用時間的倍而若新建一個數組所花費的時間就更多了
再看清除對象的過程我們知道Java語言的一個優勢就是Java程序員勿需再像C/C++程序員那樣顯式地釋放對象而由稱為垃圾收集器(Garbage Collector)的自動內存管理系統定時或在內存凸現出不足時自動回收垃圾對象所占的內存凡事有利總也有弊這雖然為Java程序設計者提供了極大的方便但同時它也帶來了較大的性能開銷這種開銷包括兩方面首先是對象管理開銷GC為了能夠正確釋放對象它必須監控每一個對象的運行狀態包括對象的申請引用被引用賦值等其次在GC開始回收垃圾對象時系統會暫停應用程序的執行而獨自占用CPU
因此如果要改善應用程序的性能一方面應盡量減少創建新對象的次數同時還應盡量減少TT的時間而這些均可以通過對象池技術來實現
對象池技術的基本原理
對象池技術基本原理的核心有兩點緩存和共享即對於那些被頻繁使用的對象在使用完後不立即將它們釋放而是將它們緩存起來以供後續的應用程序重復使用從而減少創建對象和釋放對象的次數進而改善應用程序的性能事實上由於對象池技術將對象限制在一定的數量也有效地減少了應用程序內存上的開銷
實現一個對象池一般會涉及到如下的類
)對象池工廠(ObjectPoolFactory)類
該類主要用於管理相同類型和設置的對象池(ObjectPool)它一般包含如下兩個方法
createPool用於創建特定類型和設置的對象池
destroyPool用於釋放指定的對象池
同時為保證ObjectPoolFactory的單一實例可以采用Singleton設計模式見下述getInstance方法的實現
public static 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 paraObjClass clsType) {
return new ObjectPool(paraObj clsType);
}
其中paraObj參數用於指定對象池的特征屬性clsType參數則指定了該對象池所存放對象的類型對象池(ObjectPool)創建以後下面就是利用它來管理對象了具體實現如下
public class ObjectPool {
private ParameterObject paraObj;//該對象池的屬性參數對象
private Class clsType;//該對象池中所存放對象的類型
private int currentNum = ; //該對象池當前已創建的對象數目
private Object currentObj;//該對象池當前可以借出的對象
private Vector pool;//用於存放對象的池
public ObjectPool(ParameterObject paraObj Class clsType) {
thisparaObj = paraObj;
thisclsType = clsType;
pool = new Vector();
}
public Object getObject() {
if (poolsize() <= paraObjgetMinCount()) {
if (currentNum <= paraObjgetMaxCount()) {
//如果當前池中無對象可用而且已創建的對象數目小於所限制的最大值就利用
//PoolObjectFactory創建一個新的對象
PoolableObjectFactory objFactory =PoolableObjectFactorygetInstance();
currentObj = objFactorycreate Object (clsType);
currentNum++;
} else {
//如果當前池中無對象可用而且所創建的對象數目已達到所限制的最大值
//就只能等待其它線程返回對象到池中
synchronized (this) {
try {
wait();
} catch (InterruptedException e) {
Systemoutprintln(egetMessage());
eprintStackTrace();
}
currentObj = poolfirstElement();
}
}
} else {
//如果當前池中有可用的對象就直接從池中取出對象
currentObj = poolfirstElement();
}
return currentObj;
}
public void returnObject(Object obj) {
// 確保對象具有正確的類型
if (objisInstance(clsType)) {
pooladdElement(obj);
synchronized (this) {
notifyAll();
}
} else {
throw new IllegalArgumentException(該對象池不能存放指定的對象類型);
}
}
}
從上述代碼可以看出ObjectPool利用一個javautilVector作為可擴展的對象池並通過它的構造函數來指定池化對象的Class類型及對象池的一些屬性在有對象返回到對象池時它將檢查對象的類型是否正確當對象池裡不再有可用對象時它或者等待已被使用的池化對象返回池中或者創建一個新的對象實例不過新對象實例的創建並不在ObjectPool類中而是由PoolableObjectFactory類的createObject方法來完成的具體實現如下
public Object createObject(Class clsType) {
Object obj = null;
try {
obj = clsTypenewInstance();
} catch (Exception e) {
eprintStackTrace();
}
return obj;
}
這樣通用對象池的實現就算完成了下面再看看客戶端(Client)如何來使用它假定池化對象的Class類型為StringBuffer
//創建對象池工廠
ObjectPoolFactory poolFactory = ObjectPoolFactory getInstance ();
//定義所創建對象池的屬性
ParameterObject paraObj = new ParameterObject();
//利用對象池工廠創建一個存放StringBuffer類型對象的對象池
ObjectPool pool = poolFactorycreatePool(paraObjString Bufferclass);
//從池中取出一個StringBuffer對象
StringBuffer buffer = (StringBuffer)poolgetObject();
//使用從池中取出的StringBuffer對象
bufferappend(hello);
Systemoutprintln(buffertoString());
可以看出通用對象池使用起來還是很方便的不僅可以方便地避免頻繁創建對象的開銷而且通用程度高但遺憾的是由於需要使用大量的類型定型(cast)操作再加上一些對Vector類的同步操作使得它在某些情況下對性能的改進非常有限尤其對那些創建周期比較短的對象
專用對象池的實現
由於通用對象池的管理開銷比較大某種程度上抵消了重用對象所帶來的大部分優勢為解決該問題可以采用專用對象池的方法即對象池所池化對象的Class類型不是動態指定的而是預先就已指定這樣它在實現上也會較通用對象池簡單些可以不要ObjectPoolFactory和PoolableObjectFactory類而將它們的功能直接融合到ObjectPool類具體如下(假定被池化對象的Class類型仍為StringBuffer而用省略號表示的地方表示代碼同通用對象池的實現)
public class ObjectPool {
private ParameterObject paraObj;//該對象池的屬性參數對象
private int currentNum = ; //該對象池當前已創建的對象數目
private StringBuffer currentObj;//該對象池當前可以借出的對象
private Vector pool;//用於存放對象的池
public ObjectPool(ParameterObject paraObj) {
thisparaObj = paraObj;
pool = new Vector();
}
public StringBuffer getObject() {
if (poolsize() <= paraObjgetMinCount()) {
if (currentNum <= paraObjgetMaxCount()) {
currentObj = new StringBuffer();
currentNum++;
}
}
return currentObj;
}
public void returnObject(Object obj) {
// 確保對象具有正確的類型
if (StringBufferisInstance(obj)) {
}
}
結束語
恰當地使用對象池技術能有效地改善應用程序的性能目前對象池技術已得到廣泛的應用如對於網絡和數據庫連接這類重量級的對象一般都會采用對象池技術但在使用對象池技術時也要注意如下問題
並非任何情況下都適合采用對象池技術基本上只在重復生成某種對象的操作成為影響性能的關鍵因素的時候才適合采用對象池技術而如果進行池化所能帶來的性能提高並不重要的話還是不采用對象池化技術為佳以保持代碼的簡明
要根據具體情況正確選擇對象池的實現方式如果是創建一個公用的對象池技術實現包或需要在程序中動態指定所池化對象的Class類型時才選擇通用對象池而大部分情況下采用專用對象池就可以了
From:http://tw.wingwit.com/Article/program/Java/hx/201311/25768.html