溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java對象池技術(shù)的原理及其實(shí)現(xiàn)方法

發(fā)布時(shí)間:2021-08-30 23:26:44 來源:億速云 閱讀:136 作者:chen 欄目:編程語言

這篇文章主要講解了“Java對象池技術(shù)的原理及其實(shí)現(xiàn)方法”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Java對象池技術(shù)的原理及其實(shí)現(xiàn)方法”吧!

摘 要 :本文在分析對象池技術(shù)基本原理的基礎(chǔ)上,給出了對象池技術(shù)的兩種實(shí)現(xiàn)方式。還指出了使用對象池技術(shù)時(shí)所應(yīng)注意的問題。

關(guān)鍵詞: 對象池;對象池技術(shù);Java 對象;性能

[@more@]Java對象的生命周期分析
  Java對象的生命周期大致包括三個階段:對象的創(chuàng)建,對象的使用,對象的清除。因此,對象的生命周期長度可用如下的表達(dá)式表示:T = T1 + T2 +T3。其中T1表示對象的創(chuàng)建時(shí)間,T2表示對象的使用時(shí)間,而T3則表示其清除時(shí)間。由此,我們可以看出,只有T2是真正有效的時(shí)間,而T1、T3則是對象本身的開銷。下面再看看T1、T3在對象的整個生命周期中所占的比例

  我們知道,Java對象是通過構(gòu)造函數(shù)來創(chuàng)建的,在這一過程中,該構(gòu)造函數(shù)鏈中的所有構(gòu)造函數(shù)也都會被自動調(diào)用。另外,默認(rèn)情況下,調(diào)用類的構(gòu)造函數(shù)時(shí),Java會把變量初始化成確定的值:所有的對象被設(shè)置成null,整數(shù)變量(byte、short、int、long)設(shè)置成0,float和double變量設(shè)置成0.0,邏輯值設(shè)置成false。所以用new關(guān)鍵字來新建一個對象的時(shí)間開銷是很大的,如表1所示。

 表1 一些操作所耗費(fèi)時(shí)間的對照表

運(yùn)算操作             示例                     標(biāo)準(zhǔn)化時(shí)間  
本地賦值             i = n                        1.0  
實(shí)例賦值          this.i = n                     1.2  
方法調(diào)用          Funct()                       5.9  
新建對象      New Object()                  980  
新建數(shù)組       New int[10]                  3100  

  從表1可以看出,新建一個對象需要980個單位的時(shí)間,是本地賦值時(shí)間的980倍,是方法調(diào)用時(shí)間的166倍,而若新建一個數(shù)組所花費(fèi)的時(shí)間就更多了。

  再看清除對象的過程。我們知道,Java語言的一個優(yōu)勢,就是Java程序員勿需再像C/C++程序員那樣,顯式地釋放對象,而由稱為垃圾收集器(Garbage Collector)的自動內(nèi)存管理系統(tǒng),定時(shí)或在內(nèi)存凸現(xiàn)出不足時(shí),自動回收垃圾對象所占的內(nèi)存。凡事有利總也有弊,這雖然為Java程序設(shè)計(jì)者提供了極大的方便,但同時(shí)它也帶來了較大的性能開銷。這種開銷包括兩方面,首先是對象管理開銷,GC為了能夠正確釋放對象,它必須監(jiān)控每一個對象的運(yùn)行狀態(tài),包括對象的申請、引用、被引用、賦值等。其次,在GC開始回收“垃圾”對象時(shí),系統(tǒng)會暫停應(yīng)用程序的執(zhí)行,而獨(dú)自占用CPU。

  因此,如果要改善應(yīng)用程序的性能,一方面應(yīng)盡量減少創(chuàng)建新對象的次數(shù);同時(shí),還應(yīng)盡量減少T1、T3的時(shí)間,而這些均可以通過對象池技術(shù)來實(shí)現(xiàn)。

  對象池技術(shù)的基本原理

  對象池技術(shù)基本原理的核心有兩點(diǎn):緩存和共享,即對于那些被頻繁使用的對象,在使用完后,不立即將它們釋放,而是將它們緩存起來,以供后續(xù)的應(yīng)用程序重復(fù)使用,從而減少創(chuàng)建對象和釋放對象的次數(shù),進(jìn)而改善應(yīng)用程序的性能。事實(shí)上,由于對象池技術(shù)將對象限制在一定的數(shù)量,也有效地減少了應(yīng)用程序內(nèi)存上的開銷。

  實(shí)現(xiàn)一個對象池,一般會涉及到如下的類:

  1)對象池工廠(ObjectPoolFactory)類

  該類主要用于管理相同類型和設(shè)置的對象池(ObjectPool),它一般包含如下兩個方法:

  ·createPool:用于創(chuàng)建特定類型和設(shè)置的對象池;

  ·destroyPool:用于釋放指定的對象池;

  同時(shí)為保證ObjectPoolFactory的單一實(shí)例,可以采用Singleton設(shè)計(jì)模式,見下述getInstance方法的實(shí)現(xiàn):

public static ObjectPoolFactory getInstance() {
 if (poolFactory == null) {
  poolFactory = new ObjectPoolFactory();
 }
 return poolFactory;
}

  2)參數(shù)對象(ParameterObject)類

  該類主要用于封裝所創(chuàng)建對象池的一些屬性參數(shù),如池中可存放對象的數(shù)目的最大值(maxCount)、最小值(minCount)等。

  3)對象池(ObjectPool)類

  用于管理要被池化對象的借出和歸還,并通知PoolableObjectFactory完成相應(yīng)的工作。它一般包含如下兩個方法:

   ·getObject:用于從池中借出對象;
   ·returnObject:將池化對象返回到池中,并通知所有處于等待狀態(tài)的線程;

  4)池化對象工廠(PoolableObjectFactory)類

  該類主要負(fù)責(zé)管理池化對象的生命周期,就簡單來說,一般包括對象的創(chuàng)建及銷毀。該類同ObjectPoolFactory一樣,也可將其實(shí)現(xiàn)為單實(shí)例。

  通用對象池的實(shí)現(xiàn)

  對象池的構(gòu)造和管理可以按照多種方式實(shí)現(xiàn)。最靈活的方式是將池化對象的Class類型在對象池之外指定,即在ObjectPoolFactory類創(chuàng)建對象池時(shí),動態(tài)指定該對象池所池化對象的Class類型,其實(shí)現(xiàn)代碼如下:

. . .
public ObjectPool createPool(ParameterObject paraObj,Class clsType) {
 return new ObjectPool(paraObj, clsType);
}
. . .

  其中,paraObj參數(shù)用于指定對象池的特征屬性,clsType參數(shù)則指定了該對象池所存放對象的類型。對象池(ObjectPool)創(chuàng)建以后,下面就是利用它來管理對象了,具體實(shí)現(xiàn)如下:

public class ObjectPool {
 private ParameterObject paraObj;//該對象池的屬性參數(shù)對象
 private Class clsType;//該對象池中所存放對象的類型
 private int currentNum = 0; //該對象池當(dāng)前已創(chuàng)建的對象數(shù)目
 private Object currentObj;//該對象池當(dāng)前可以借出的對象
 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()) {
    //如果當(dāng)前池中無對象可用,而且已創(chuàng)建的對象數(shù)目小于所限制的最大值,就利用
    //PoolObjectFactory創(chuàng)建一個新的對象
    PoolableObjectFactory objFactory =PoolableObjectFactory.getInstance();
    currentObj = objFactory.create Object (clsType);
    currentNum++;
   } else {
    //如果當(dāng)前池中無對象可用,而且所創(chuàng)建的對象數(shù)目已達(dá)到所限制的最大值,
    //就只能等待其它線程返回對象到池中
    synchronized (this) {
     try {
      wait();
     } catch (InterruptedException e) {
      System.out.println(e.getMessage());
      e.printStackTrace();
     }
     currentObj = pool.firstElement();
    }
   }
  } else {
   //如果當(dāng)前池中有可用的對象,就直接從池中取出對象
   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作為可擴(kuò)展的對象池,并通過它的構(gòu)造函數(shù)來指定池化對象的Class類型及對象池的一些屬性。在有對象返回到對象池時(shí),它將檢查對象的類型是否正確。當(dāng)對象池里不再有可用對象時(shí),它或者等待已被使用的池化對象返回池中,或者創(chuàng)建一個新的對象實(shí)例。不過,新對象實(shí)例的創(chuàng)建并不在ObjectPool類中,而是由PoolableObjectFactory類的createObject方法來完成的,具體實(shí)現(xiàn)如下:

. . .
public Object createObject(Class clsType) {
 Object obj = null;
 try {
  obj = clsType.newInstance();
 } catch (Exception e) {
  e.printStackTrace();
 }
 return obj;
}
. . .


  這樣,通用對象池的實(shí)現(xiàn)就算完成了,下面再看看客戶端(Client)如何來使用它,假定池化對象的Class類型為StringBuffer:

. . .
//創(chuàng)建對象池工廠
ObjectPoolFactory poolFactory = ObjectPoolFactory. getInstance ();
//定義所創(chuàng)建對象池的屬性
ParameterObject paraObj = new ParameterObject(2,1);
//利用對象池工廠,創(chuàng)建一個存放StringBuffer類型對象的對象池
ObjectPool pool = poolFactory.createPool(paraObj,String Buffer.class);
//從池中取出一個StringBuffer對象
StringBuffer buffer = (StringBuffer)pool.getObject();
//使用從池中取出的StringBuffer對象
buffer.append("hello");
System.out.println(buffer.toString());
. . .

  可以看出,通用對象池使用起來還是很方便的,不僅可以方便地避免頻繁創(chuàng)建對象的開銷,而且通用程度高。但遺憾的是,由于需要使用大量的類型定型(cast)操作,再加上一些對Vector類的同步操作,使得它在某些情況下對性能的改進(jìn)非常有限,尤其對那些創(chuàng)建周期比較短的對象。

  專用對象池的實(shí)現(xiàn) 

  由于通用對象池的管理開銷比較大,某種程度上抵消了重用對象所帶來的大部分優(yōu)勢。為解決該問題,可以采用專用對象池的方法。即對象池所池化對象的Class類型不是動態(tài)指定的,而是預(yù)先就已指定。這樣,它在實(shí)現(xiàn)上也會較通用對象池簡單些,可以不要ObjectPoolFactory和PoolableObjectFactory類,而將它們的功能直接融合到ObjectPool類,具體如下(假定被池化對象的Class類型仍為StringBuffer,而用省略號表示的地方,表示代碼同通用對象池的實(shí)現(xiàn)):

public class ObjectPool {
 private ParameterObject paraObj;//該對象池的屬性參數(shù)對象
 private int currentNum = 0; //該對象池當(dāng)前已創(chuàng)建的對象數(shù)目
 private StringBuffer currentObj;//該對象池當(dāng)前可以借出的對象
 private Vector pool;//用于存放對象的池
 public ObjectPool(ParameterObject paraObj) {
  this.paraObj = paraObj;
  pool = new Vector();
 }
 public StringBuffer getObject() {
  if (pool.size() <= paraObj.getMinCount()) {
   if (currentNum <= paraObj.getMaxCount()) {
    currentObj = new StringBuffer();
    currentNum++;
   }
   . . .
  }
  return currentObj;
 }
 public void returnObject(Object obj) {
  // 確保對象具有正確的類型
  if (StringBuffer.isInstance(obj)) {
   . . .
  }
 }

感謝各位的閱讀,以上就是“Java對象池技術(shù)的原理及其實(shí)現(xiàn)方法”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對Java對象池技術(shù)的原理及其實(shí)現(xiàn)方法這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI