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

Java對(duì)象的生命周期分析

Java對(duì)象的生命周期大致包括三個(gè)階段:

  • 對(duì)象的創(chuàng)建
  • 對(duì)象的使用
  • 對(duì)象的清

因此柔纵,對(duì)象的生命周期長(zhǎng)度可用如下的表達(dá)式表示:T = T1 + T2 +T3
其中T1表示對(duì)象的創(chuàng)建時(shí)間夺姑,T2表示對(duì)象的使用時(shí)間蛹锰,而T3則表示其清除時(shí)間
由此,我們可以看出熔脂,只有T2是真正有效的時(shí)間佩研,而T1、T3則是對(duì)象本身的開銷

下面再看看T1霞揉、T3在對(duì)象的整個(gè)生命周期中所占的比例旬薯。

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

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


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

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

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

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

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

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

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

  • createPool:用于創(chuàng)建特定類型和設(shè)置的對(duì)象池缆蝉;
  • destroyPool:用于釋放指定的對(duì)象池;

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

  • 對(duì)象池創(chuàng)建(參考GenericObjectPool):
    public GenericObjectPool(PoolableObjectFactory factory, GenericObjectPool.Config config)
    此方法創(chuàng)建一個(gè)GenericObjectPool實(shí)例,GenericObjectPool類已經(jīng)實(shí)現(xiàn)了和對(duì)象池有關(guān)的所有核心操作,開發(fā)者可以通過(guò)繼承或者封裝的方式來(lái)使用它.通過(guò)此構(gòu)造函數(shù),我們能夠清晰的看到,一個(gè)Pool中需要指定PoolableObjectFactory 實(shí)例,以及此對(duì)象池的Config信息.PoolableObjectFactory主要用來(lái)"創(chuàng)建新對(duì)象",比如當(dāng)對(duì)象池中的對(duì)象不足時(shí),可以使用PoolableObjectFactory.makeObject()方法來(lái)創(chuàng)建對(duì)象,并交付給Pool管理.

此構(gòu)造函數(shù)實(shí)例化了一個(gè)LinkedList作為"對(duì)象池"容器,用來(lái)存取"對(duì)象".此外還會(huì)根據(jù)timeBetweenEvictionRunsMillis的值來(lái)決定是否啟動(dòng)一個(gè)后臺(tái)線程,此線程用來(lái)周期性掃描pool中的對(duì)象列表,已檢測(cè)"對(duì)象池中的對(duì)象"空閑(idle)的時(shí)間是否達(dá)到了閥值,如果是,則移除此對(duì)象.

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

該類主要用于封裝所創(chuàng)建對(duì)象池的對(duì)象存取機(jī)制诸尽,如池中可存放對(duì)象的數(shù)目的最大值(maxCount)原杂、最小值(minCount)等。

3)對(duì)象池(ObjectPool)類

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

  • Object borrowObject() : 從Pool獲取一個(gè)對(duì)象,此操作將導(dǎo)致一個(gè)"對(duì)象"從Pool移除(脫離Pool管理),調(diào)用者可以在獲得"對(duì)象"引用后即可使用,且需要在使用結(jié)束后"歸還".
public Object borrowObject() throws Exception {  
    Object value = null;  
    synchronized (this) {  
        if(!_pool.isEmpty()){  
            value = _pool.remove();  
        }  
          
    }         
    for(;;) {       
        //如果Pool中沒(méi)有"對(duì)象",則根據(jù)相應(yīng)的"耗盡"策略  
        if(value == null) {  
            switch(whenExhaustedAction) {  
                //如果耗盡,仍繼續(xù)創(chuàng)建新"對(duì)象"  
                case WHEN_EXHAUSTED_GROW:  
                    value = _factory.makeObject();  
                    break;  
                //如果耗盡,則終止,此時(shí)以異常的方式退出.  
                case WHEN_EXHAUSTED_FAIL:  
                    throw new NoSuchElementException("Pool exhausted");  
                //如果耗盡,則阻塞,直到有"對(duì)象"歸還  
                case WHEN_EXHAUSTED_BLOCK:  
                    try {  
                        synchronized (value) {  
                            if (value == null) {  
                                //maxWait為Config中指定的"最大等待時(shí)間"  
                                if(maxWait <= 0) {  
                                    latch.wait();  
                                } else {  
                                        latch.wait(waitTime);  
                                }  
                            } else {  
                                break;  
                            }  
                        }  
                    } catch(InterruptedException e) {         
                        //  
                        break;  
                    }  
                      
                default://  
            }  
        }  
  
        try {  
            _factory.activateObject(latch.getPair().value);  
            if(_testOnBorrow &&  
                    !_factory.validateObject(latch.getPair().value)) {  
                throw new Exception("ValidateObject failed");  
            }  
           return value;  
        }  
        catch (Throwable e) {  
            try {  
                _factory.destroyObject(latch.getPair().value);  
            } catch (Throwable e2) {  
                //  
            }  
        }  
    }  
}  
  • void returnObject(Object obj) : "歸還"對(duì)象,當(dāng)"對(duì)象"使用結(jié)束后,需要?dú)w還到Pool中,才能維持Pool中對(duì)象的數(shù)量可控,如果不歸還到Pool,那么將意味著在Pool之外,將有大量的"對(duì)象"存在,那么就使用了"對(duì)象池"的意義.如下為偽代碼:
public void returnObject(Object obj) throws Exception {  
    try {  
        boolean success = true;//  
        if(_testOnReturn && !(_factory.validateObject(obj))) {  
            success = false;  
        } else {  
            _factory.passivateObject(obj);  
        }  
  
        synchronized (this) {  
            //檢測(cè)pool中已經(jīng)空閑的對(duì)象個(gè)數(shù)是否達(dá)到閥值.  
            if((_maxIdle >= 0) && (_pool.size() >= _maxIdle)) {  
                success = false;  
            } else if(success) {  
                _pool.addFirst(new ObjectTimestampPair(obj));  
            }  
        }  
  
        // Destroy the instance if necessary  
        if(!success) {  
            try {  
                _factory.destroyObject(obj);  
            } catch(Exception e) {  
                // ignored  
            }  
        }  
    } catch (Exception e) {  
        //  
    }  
}  

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

該類主要負(fù)責(zé)管理池化對(duì)象的生命周期,就簡(jiǎn)單來(lái)說(shuō)往产,一般包括對(duì)象的創(chuàng)建及銷毀被碗。該類同ObjectPoolFactory一樣,也可將其實(shí)現(xiàn)為單實(shí)例仿村。
通過(guò)使用ObjectFactory(工廠模式)的方式將"對(duì)象池中的對(duì)象"的創(chuàng)建/檢測(cè)/銷毀等特性解耦出來(lái),這是一個(gè)非常良好的設(shè)計(jì)思想.此接口有一個(gè)抽象類BasePoolableObjectFactory,可供開發(fā)者繼承和實(shí)現(xiàn).

  • Object makeObject() : 創(chuàng)建一個(gè)新對(duì)象;當(dāng)對(duì)象池中的對(duì)象個(gè)數(shù)不足時(shí),將會(huì)使用此方法來(lái)"輸出"一個(gè)新的"對(duì)象",并交付給對(duì)象池管理.
  • void destroyObject(Object obj) : 銷毀對(duì)象,如果對(duì)象池中檢測(cè)到某個(gè)"對(duì)象"idle的時(shí)間超時(shí),或者操作者向?qū)ο蟪?歸還對(duì)象"時(shí)檢測(cè)到"對(duì)象"已經(jīng)無(wú)效,那么此時(shí)將會(huì)導(dǎo)致"對(duì)象銷毀";"銷毀對(duì)象"的操作設(shè)計(jì)相差甚遠(yuǎn),但是必須明確:當(dāng)調(diào)用此方法時(shí),"對(duì)象"的生命周期必須結(jié)束.如果object是線程,那么此時(shí)線程必須退出;如果object是socket操作,那么此時(shí)socket必須關(guān)閉;如果object是文件流操作,那么此時(shí)"數(shù)據(jù)flush"且正常關(guān)閉.
  • boolean validateObject(Object obj) : 檢測(cè)對(duì)象是否"有效";Pool中不能保存無(wú)效的"對(duì)象",因此"后臺(tái)檢測(cè)線程"會(huì)周期性的檢測(cè)Pool中"對(duì)象"的有效性,如果對(duì)象無(wú)效則會(huì)導(dǎo)致此對(duì)象從Pool中移除,并destroy;此外在調(diào)用者從Pool獲取一個(gè)"對(duì)象"時(shí),也會(huì)檢測(cè)"對(duì)象"的有效性,確保不能講"無(wú)效"的對(duì)象輸出給調(diào)用者;當(dāng)調(diào)用者使用完畢將"對(duì)象歸還"到Pool時(shí),仍然會(huì)檢測(cè)對(duì)象的有效性.所謂有效性,就是此"對(duì)象"的狀態(tài)是否符合預(yù)期,是否可以對(duì)調(diào)用者直接使用;如果對(duì)象是Socket,那么它的有效性就是socket的通道是否暢通/阻塞是否超時(shí)等.
  • void activateObject(Object obj) : "激活"對(duì)象,當(dāng)Pool中決定移除一個(gè)對(duì)象交付給調(diào)用者時(shí)額外的"激活"操作,比如可以在activateObject方法中"重置"參數(shù)列表讓調(diào)用者使用時(shí)感覺像一個(gè)"新創(chuàng)建"的對(duì)象一樣;如果object是一個(gè)線程,可以在"激活"操作中重置"線程中斷標(biāo)記",或者讓線程從阻塞中喚醒等;如果object是一個(gè)socket,那么可以在"激活操作"中刷新通道,或者對(duì)socket進(jìn)行鏈接重建(假如socket意外關(guān)閉)等.
  • void void passivateObject(Object obj) : "鈍化"對(duì)象,當(dāng)調(diào)用者"歸還對(duì)象"時(shí),Pool將會(huì)"鈍化對(duì)象";鈍化的言外之意,就是此"對(duì)象"暫且需要"休息"一下.如果object是一個(gè)socket,那么可以passivateObject中清除buffer,將socket阻塞;如果object是一個(gè)線程,可以在"鈍化"操作中將線程sleep或者將線程中的某個(gè)對(duì)象wait.需要注意的時(shí),activateObject和passivateObject兩個(gè)方法需要對(duì)應(yīng),避免死鎖或者"對(duì)象"狀態(tài)的混亂.

首選需要聲明,不同的"對(duì)象池"(或者連接池)在設(shè)計(jì)上可能存在很大的區(qū)別,但是在思想上大同小異

基本對(duì)象獲取與歸還原理

image.png

管理控制策略PoolConfig

  • maxActive: 鏈接池中最大連接數(shù),默認(rèn)為8.
  • maxIdle: 鏈接池中最大空閑的連接數(shù),默認(rèn)為8.
  • minIdle: 連接池中最少空閑的連接數(shù),默認(rèn)為0.
  • maxWait: 當(dāng)連接池資源耗盡時(shí)锐朴,調(diào)用者最大阻塞的時(shí)間,超時(shí)將跑出異常蔼囊。單位焚志,毫秒數(shù);默認(rèn)為-1.表示永不超時(shí).
  • minEvictableIdleTimeMillis: 連接空閑的最小時(shí)間,達(dá)到此值后空閑連接將可能會(huì)被移除畏鼓。負(fù)值(-1)表示不移除酱酬。
  • softMinEvictableIdleTimeMillis: 連接空閑的最小時(shí)間,達(dá)到此值后空閑鏈接將會(huì)被移除云矫,且保留“minIdle”個(gè)空閑連接數(shù)膳沽。默認(rèn)為-1.
  • numTestsPerEvictionRun: 對(duì)于“空閑鏈接”檢測(cè)線程而言,每次檢測(cè)的鏈接資源的個(gè)數(shù)。默認(rèn)為3.
  • testOnBorrow: 向調(diào)用者輸出“鏈接”資源時(shí)挑社,是否檢測(cè)是有有效陨界,如果無(wú)效則從連接池中移除,并嘗試獲取繼續(xù)獲取痛阻。默認(rèn)為false菌瘪。建議保持默認(rèn)值.
  • testOnReturn: 向連接池“歸還”鏈接時(shí),是否檢測(cè)“鏈接”對(duì)象的有效性阱当。默認(rèn)為false俏扩。建議保持默認(rèn)值.
  • testWhileIdle: 向調(diào)用者輸出“鏈接”對(duì)象時(shí),是否檢測(cè)它的空閑超時(shí)弊添;默認(rèn)為false录淡。如果“鏈接”空閑超時(shí),將會(huì)被移除表箭。建議保持默認(rèn)值.
  • timeBetweenEvictionRunsMillis: “空閑鏈接”檢測(cè)線程赁咙,檢測(cè)的周期钮莲,毫秒數(shù)免钻。如果為負(fù)值,表示不運(yùn)行“檢測(cè)線程”崔拥。默認(rèn)為-1.
  • whenExhaustedAction: 當(dāng)“連接池”中active數(shù)量達(dá)到閥值時(shí)极舔,即“鏈接”資源耗盡時(shí),連接池需要采取的手段, 默認(rèn)為1:
    -> 0 : 拋出異常链瓦,
    -> 1 : 阻塞拆魏,直到有可用鏈接資源
    -> 2 : 強(qiáng)制創(chuàng)建新的鏈接資源

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

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

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

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

public class ObjectPool {
 private ParameterObject paraObj;//該對(duì)象池的屬性參數(shù)對(duì)象
 private Class clsType;//該對(duì)象池中所存放對(duì)象的類型
 private int currentNum = 0; //該對(duì)象池當(dāng)前已創(chuàng)建的對(duì)象數(shù)目
 private Object currentObj;//該對(duì)象池當(dāng)前可以借出的對(duì)象
 private Vector pool;//用于存放對(duì)象的池
 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)前池中無(wú)對(duì)象可用,而且已創(chuàng)建的對(duì)象數(shù)目小于所限制的最大值突梦,就利用
    //PoolObjectFactory創(chuàng)建一個(gè)新的對(duì)象
    PoolableObjectFactory objFactory =PoolableObjectFactory.getInstance();
    currentObj = objFactory.create Object (clsType);
    currentNum++;
   } else {
    //如果當(dāng)前池中無(wú)對(duì)象可用诫舅,而且所創(chuàng)建的對(duì)象數(shù)目已達(dá)到所限制的最大值,
    //就只能等待其它線程返回對(duì)象到池中
    synchronized (this) {
     try {
      wait();
     } catch (InterruptedException e) {
      System.out.println(e.getMessage());
      e.printStackTrace();
     }
     currentObj = pool.firstElement();
    }
   }
  } else {
   //如果當(dāng)前池中有可用的對(duì)象宫患,就直接從池中取出對(duì)象
   currentObj = pool.firstElement();
  }
  return currentObj;
}
  public void returnObject(Object obj) {
   // 確保對(duì)象具有正確的類型
   if (obj.isInstance(clsType)) {
    pool.addElement(obj);
    synchronized (this) {
     notifyAll();
    }
   } else {
    throw new IllegalArgumentException("該對(duì)象池不能存放指定的對(duì)象類型");
   }
  }
}

從上述代碼可以看出刊懈,ObjectPool利用一個(gè)java.util.Vector作為可擴(kuò)展的對(duì)象池,并通過(guò)它的構(gòu)造函數(shù)來(lái)指定池化對(duì)象的Class類型及對(duì)象池的一些屬性。在有對(duì)象返回到對(duì)象池時(shí)虚汛,它將檢查對(duì)象的類型是否正確当宴。當(dāng)對(duì)象池里不再有可用對(duì)象時(shí),它或者等待已被使用的池化對(duì)象返回池中泽疆,或者創(chuàng)建一個(gè)新的對(duì)象實(shí)例户矢。不過(guò),新對(duì)象實(shí)例的創(chuàng)建并不在ObjectPool類中殉疼,而是由PoolableObjectFactory類的createObject方法來(lái)完成的梯浪,具體實(shí)現(xiàn)如下:

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

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

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

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

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

由于通用對(duì)象池的管理開銷比較大,某種程度上抵消了重用對(duì)象所帶來(lái)的大部分優(yōu)勢(shì)刨疼。為解決該問(wèn)題泉唁,可以采用專用對(duì)象池的方法。即對(duì)象池所池化對(duì)象的Class類型不是動(dòng)態(tài)指定的揩慕,而是預(yù)先就已指定亭畜。這樣,它在實(shí)現(xiàn)上也會(huì)較通用對(duì)象池簡(jiǎn)單些迎卤,可以不要ObjectPoolFactory和PoolableObjectFactory類拴鸵,而將它們的功能直接融合到ObjectPool類,具體如下(假定被池化對(duì)象的Class類型仍為StringBuffer止吐,而用省略號(hào)表示的地方宝踪,表示代碼同通用對(duì)象池的實(shí)現(xiàn)):

public class ObjectPool {
 private ParameterObject paraObj;//該對(duì)象池的屬性參數(shù)對(duì)象
 private int currentNum = 0; //該對(duì)象池當(dāng)前已創(chuàng)建的對(duì)象數(shù)目
 private StringBuffer currentObj;//該對(duì)象池當(dāng)前可以借出的對(duì)象
 private Vector pool;//用于存放對(duì)象的池
 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) {
  // 確保對(duì)象具有正確的類型
  if (StringBuffer.isInstance(obj)) {
   . . . 
  }
 }

小結(jié)

恰當(dāng)?shù)厥褂脤?duì)象池技術(shù),能有效地改善應(yīng)用程序的性能碍扔。目前瘩燥,對(duì)象池技術(shù)已得到廣泛的應(yīng)用,如對(duì)于網(wǎng)絡(luò)和數(shù)據(jù)庫(kù)連接這類重量級(jí)的對(duì)象不同,一般都會(huì)采用對(duì)象池技術(shù)厉膀。但在使用對(duì)象池技術(shù)時(shí)也要注意如下問(wèn)題:

·并非任何情況下都適合采用對(duì)象池技術(shù)溶耘。基本上服鹅,只在重復(fù)生成某種對(duì)象的操作成為影響性能的關(guān)鍵因素的時(shí)候凳兵,才適合采用對(duì)象池技術(shù)。而如果進(jìn)行池化所能帶來(lái)的性能提高并不重要的話企软,還是不采用對(duì)象池化技術(shù)為佳庐扫,以保持代碼的簡(jiǎn)明。

·要根據(jù)具體情況正確選擇對(duì)象池的實(shí)現(xiàn)方式仗哨。如果是創(chuàng)建一個(gè)公用的對(duì)象池技術(shù)實(shí)現(xiàn)包形庭,或需要在程序中動(dòng)態(tài)指定所池化對(duì)象的Class類型時(shí),才選擇通用對(duì)象池厌漂。而大部分情況下萨醒,采用專用對(duì)象池就可以了。

代碼實(shí)例

本實(shí)例主要用來(lái)演示一個(gè)"TCP連接池".
1) ConnectionPoolFactory.java:

public class ConnectionPoolFactory {  
  
    private GenericObjectPool pool;  
  
    public ConnectionPoolFactory(Config config,String ip,int port){  
        ConnectionFactory factory = new ConnectionFactory(ip, port);  
        pool = new GenericObjectPool(factory, config);  
    }  
      
    public Socket getConnection() throws Exception{  
        return (Socket)pool.borrowObject();  
    }  
      
    public void releaseConnection(Socket socket){  
        try{  
            pool.returnObject(socket);  
        }catch(Exception e){  
            if(socket != null){  
                try{  
                    socket.close();  
                }catch(Exception ex){  
                    //  
                }  
            }  
        }  
    }  
      
    /** 
     * inner  
     * @author qing 
     * 
     */  
    class ConnectionFactory extends BasePoolableObjectFactory {  
  
        private InetSocketAddress address;  
          
        public ConnectionFactory(String ip,int port){  
            address = new InetSocketAddress(ip, port);  
        }  
          
        @Override  
        public Object makeObject() throws Exception {  
            Socket socket = new Socket();  
            socket.connect(address);  
            return socket;  
        }  
          
        public void destroyObject(Object obj) throws Exception  {  
            if(obj instanceof Socket){  
                ((Socket)obj).close();  
            }  
        }  
  
        public boolean validateObject(Object obj) {  
            if(obj instanceof Socket){  
                Socket socket = ((Socket)obj);  
                if(!socket.isConnected()){  
                    return false;  
                }  
                if(socket.isClosed()){  
                    return false;  
                }  
                return true;  
            }  
            return false;  
        }  
    }  
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末苇倡,一起剝皮案震驚了整個(gè)濱河市富纸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌旨椒,老刑警劉巖晓褪,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異钩乍,居然都是意外死亡辞州,警方通過(guò)查閱死者的電腦和手機(jī)怔锌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門寥粹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人埃元,你說(shuō)我怎么就攤上這事涝涤。” “怎么了岛杀?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵阔拳,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我类嗤,道長(zhǎng)糊肠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任遗锣,我火速辦了婚禮货裹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘精偿。我一直安慰自己弧圆,他們只是感情好赋兵,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著搔预,像睡著了一般霹期。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拯田,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天历造,我揣著相機(jī)與錄音,去河邊找鬼船庇。 笑死帕膜,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的溢十。 我是一名探鬼主播垮刹,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼张弛!你這毒婦竟也來(lái)了荒典?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤吞鸭,失蹤者是張志新(化名)和其女友劉穎寺董,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體刻剥,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡遮咖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了造虏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片御吞。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖漓藕,靈堂內(nèi)的尸體忽然破棺而出陶珠,到底是詐尸還是另有隱情,我是刑警寧澤享钞,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布揍诽,位于F島的核電站,受9級(jí)特大地震影響栗竖,放射性物質(zhì)發(fā)生泄漏暑脆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一狐肢、第九天 我趴在偏房一處隱蔽的房頂上張望添吗。 院中可真熱鬧,春花似錦处坪、人聲如沸根资。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)玄帕。三九已至部脚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間裤纹,已是汗流浹背委刘。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鹰椒,地道東北人锡移。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓漆际,卻偏偏與公主長(zhǎng)得像淆珊,于是被迫代替她去往敵國(guó)和親奸汇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理擂找,服務(wù)發(fā)現(xiàn)戳吝,斷路器,智...
    卡卡羅2017閱讀 134,659評(píng)論 18 139
  • 轉(zhuǎn)自:http://blog.csdn.net/jackfrued/article/details/4492194...
    王帥199207閱讀 8,529評(píng)論 3 93
  • 從三月份找實(shí)習(xí)到現(xiàn)在听哭,面了一些公司塘雳,掛了不少陆盘,但最終還是拿到小米、百度粉捻、阿里礁遣、京東、新浪、CVTE杏头、樂(lè)視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,253評(píng)論 11 349
  • 在最美的年紀(jì)遇見你,正如這一年呢燥,這個(gè)季節(jié)寓娩,我和大學(xué)有個(gè)“約會(huì)”叛氨。 都說(shuō)人生是一本書,那青春則是其中最精彩的...
    飄零的回憶閱讀 380評(píng)論 0 2
  • 版權(quán)信息的常用屬性
    我_巨可愛閱讀 142評(píng)論 0 0