從表1可以看出,新建一個對象需要980個單位的時間,是本地賦值時間的980倍,是方法調用時間的166倍,而若新建一個數組所花費的時間就更多了。
再看清除對象的過程。我們知道,Java語言的一個優勢,就是Java程序員勿需再像C/C++程序員那樣,顯式地釋放對象,而由稱為垃圾收集器(Garbage Collector)的自動內存管理系統,定時或在內存凸現出不足時,自動回收垃圾對象所占的內存。凡事有利總也有弊,這雖然為Java程序設計者提供了極大的方便,但同時它也帶來了較大的性能開銷。這種開銷包括兩方面,首先是對象管理開銷,GC為了能夠正確釋放對象,它必須監控每一個對象的運行狀態,包括對象的申請、引用、被引用、賦值等。其次,在GC開始回收“垃圾”對象時,系統會暫停應用程序的執行,而獨自占用CPU。
因此,如果要改善應用程序的性能,一方面應盡量減少創建新對象的次數;同時,還應盡量減少T1、T3的時間,而這些均可以通過對象池技術來實現。
對象池技術的基本原理
對象池技術基本原理的核心有兩點:緩存和共享,即對於那些被頻繁使用的對象,在使用完後,不立即將它們釋放,而是將它們緩存起來,以供後續的應用程序重復使用,從而減少創建對象和釋放對象的次數,進而改善應用程序的性能。事實上,由於對象池技術將對象限制在一定的數量,也有效地減少了應用程序內存上的開銷。
實現一個對象池,一般會涉及到如下的類:
1)對象池工廠(ObjectPoolFactory)類
該類主要用於管理相同類型和設置的對象池(ObjectPool),它一般包含如下兩個方法:
·createPool:用於創建特定類型和設置的對象池;
·destroyPool:用於釋放指定的對象池;
同時為保證ObjectPoolFactory的單一實例,可以采用Singleton設計模式,見下述getInstance方法的實現:
public static ObjectPoolFactory getInstance() {
if (poolFactory == null) {
poolFactory = new ObjectPoolFactory();
}
return poolFactory;
}
2)參數對象(ParameterObject)類
該類主要用於封裝所創建對象池的一些屬性參數,如池中可存放對象的數目的最大值(maxCount)、最小值(minCount)等。
3)對象池(ObjectPool)類
用於管理要被池化對象的借出和歸還,並通知PoolableObjectFactory完成相應的工作。它一般包含如下兩個方法:
·getObject:用於從池中借出對象;
·returnObject:將池化對象返回到池中,並通知所有處於等待狀態的線程;
4)池化對象工廠(PoolableObjectFactory)類
該類主要負責管理池化對象的生命周期,就簡單來說,一般包括對象的創建及銷毀。該類同ObjectPoolFactory一樣,也可將其實現為單實例。
通用對象池的實現
對象池的構造和管理可以按照多種方式實現。最靈活的方式是將池化對象的Class類型在對象池之外指定,即在ObjectPoolFactory類創建對象池時,動態指定該對象池所池化對象的Class類型,其實現代碼如下:
. . .
public ObjectPool createPool(ParameterObject paraObj,Class clsType) {
return new ObjectPool(paraObj, clsType);
}
. . .
其中,paraObj參數用於指定對象池的特征屬性,clsType參數則指定了該對象池所存放對象的類型。對象池(ObjectPool)創建以後,下面就是利用它來管理對象了,具體實現如下:
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.create Object (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 (obj.isInstance(clsType)) {
pool.addElement(obj);
synchronized (this) {
notifyAll();
}
} else {
throw new IllegalArgumentException("該對象池不能存放指定的對象類型");
}
}
}
從上述代碼可以看出,ObjectPool利用一個Java.util.Vector作為可擴展的對象池,並通過它的構造函數來指定池化對象的Class類型及對象池的一些屬性。在有對象返回到對象池時,它將檢查對象的類型是否正確。當對象池裡不再有可用對象時,它或者等待已被使用的池化對象返回池中,或者創建一個新的對象實例。不過,新對象實例的創建並不在ObjectPool類中,而是由PoolableObjectFactory類的createObject方法來完成的,具體實現如下:
. . .
public Object createObject(Class clsType) {
Object obj = null;
try {
obj = clsType.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
. . .
這樣,通用對象池的實現就算完成了,下面再看看客戶端(ClIEnt)如何來使用它,假定池化對象的Class類型為StringBuffer:
. . .
//創建對象池工廠
ObjectPoolFactory poolFactory = ObjectPoolFactory. getInstance ();
//定義所創建對象池的屬性
ParameterObject paraObj = new ParameterObject(2,1);
//利用對象池工廠,創建一個存放StringBuffer類型對象的對象池
ObjectPool pool = poolFactory.createPool(paraObj,String Buffer.class);
//從池中取出一個StringBuffer對象
StringBuffer buffer = (StringBuffer)pool.getObject();
//使用從池中取出的StringBuffer對象
buffer.append("hello");
System.out.println(buffer.toString());
. . .
可以看出,通用對象池使用起來還是很方便的,不僅可以方便地避免頻繁創建對象的開銷,而且通用程度高。但遺憾的是,由於需要使用大量的類型定型(cast)操作,再加上一些對Vector類的同步操作,使得它在某些情況下對性能的改進非常有限,尤其對那些創建周期比較短的對象。
專用對象池的實現
由於通用對象池的管理開銷比較大,某種程度上抵消了重用對象所帶來的大部分優勢。為解決該問題,可以采用專用對象池的方法。即對象池所池化對象的Class類型不是動態指定的,而是預先就已指定。這樣,它在實現上也會較通用對象池簡單些,可以不要ObjectPoolFactory和PoolableObjectFactory類,而將它們的功能直接融合到ObjectPool類,具體如下(假定被池化對象的Class類型仍為StringBuffer,而用省略號表示的地方,表示代碼同通用對象池的實現):