<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Change Dir

    先知cd——熱愛生活是一切藝術的開始

    統計

    留言簿(18)

    積分與排名

    “牛”們的博客

    各個公司技術

    我的鏈接

    淘寶技術

    閱讀排行榜

    評論排行榜

    commons-pool學習筆記

    Object pool就是一個管理對象的池子。新版本利用jdk 1.5以后的特性,結合泛型,而不是利用Object來實現了。

    主要就靠3個接口來管理:

    ObjectPool, 定義了池接口,就是說,以后的對象池,至少模子是這個樣子的~~主要兩個實現抽象類:BaseObjectPool和KeyedObjectPool。有一些基本方法比如從對象池取對象,調用borrowObject()方法,將對象放回使用returnObject()方法。清空選擇clear,而不需要對象池選擇關閉時使用close等。在具體的Pool實現中,會依賴PoolableObjectFactory接口。

    PoolableObjectFactory,怎么理解這個接口呢?其實在ObjectPool中我們看到只是聲明了一些調用和放回對象的方法,可以理解為真正我們在操作一個pool,這就是一個數據結構。然而pool中的對象創建、管理、銷毀等事務pool管不了了。因此框架又定義了這樣一個factory去管理這些對象。該接口有makeObject方法,我們自己的factory實現里可以利用這個方法去創建個性化的對象。有創建就有銷毀,destroyObject(T obj)方法就用來銷毀對象。同時還有activateObject(T obj)方法用來激活對象,也就是說令對象可用。有passivateObject(T obj)方法用來將對象作為idle狀態。同時還有validateObject(T obj)方法來檢驗對象是否可以由pool安全返回。

    ObjectPoolFactory,作為最后一個接口,我感覺這個factory應該算是用處不特別大吧。顧名思義,用來管理pool的一個factory。我們的應用如果需要的話,可能不止一個pool。由一個factory去管理,明顯合理的,而且factory模式也是pool框架的特色。該接口只有一個方法,那就是createObjectPool()。

     

    框架的類圖主要關系就是這樣

    clip_image002

    圖片來源是http://commons.apache.org/pool/guide/classdiagrams.html。只需要看清楚幾個接口的關系就可以了。

    那么最好還是舉例看看一個pool如何使用吧。例子是commons-pool1.4版本,jdk1.6

    <代碼修改自參考資料http://www.ibm.com/developerworks/cn/java/l-common-pool/>

    首先定義一個對象(一般使用線程池的原則是對象比較大,所以我們就叫它大對象):

       1: /**
       2:  * 
       3:  */
       4: package common.pool;
       5:  
       6: /**
       7:  * @author Administrator
       8:  *
       9:  */
      10: public class BigObject {
      11:  
      12:     private boolean active;
      13:     
      14:     public boolean isActive() {
      15:         return active;
      16:     }
      17:  
      18:     public void setActive(boolean active) {
      19:         this.active = active;
      20:     }
      21:  
      22:     public BigObject() {
      23:         active = true;
      24:         System.out.println("i am a big object!!!");
      25:     }
      26:     
      27:     public String toString() {
      28:         return "big object "+ this.hashCode();
      29:     }
      30: }

    接著去實現PoolableObjectFactory:

       1: /**
       2:  * 
       3:  */
       4: package common.pool;
       5:  
       6: import org.apache.commons.pool.*;
       7: /**
       8:  * @author Administrator
       9:  *
      10:  */
      11: public class TestFactory implements PoolableObjectFactory{
      12:  
      13:     @Override
      14:     public void activateObject(Object arg0) throws Exception {
      15:         // TODO Auto-generated method stub
      16:         ((BigObject)arg0).setActive(true);
      17:     }
      18:  
      19:     @Override
      20:     public void destroyObject(Object arg0) throws Exception {
      21:         // TODO Auto-generated method stub
      22:         arg0 = null;
      23:     }
      24:  
      25:     @Override
      26:     public Object makeObject() throws Exception {
      27:         // TODO Auto-generated method stub
      28:         BigObject bo = new BigObject();
      29:         return bo;
      30:     }
      31:  
      32:     @Override
      33:     public void passivateObject(Object arg0) throws Exception {
      34:         // TODO Auto-generated method stub
      35:         ((BigObject)arg0).setActive(false);
      36:     }
      37:  
      38:     @Override
      39:     public boolean validateObject(Object arg0) {
      40:         // TODO Auto-generated method stub
      41:         if(((BigObject)arg0).isActive())
      42:             return true;
      43:         else
      44:             return false;
      45:     }
      46:  
      47: }

    最后測試:

       1: /**
       2:  * 
       3:  */
       4: package common.pool;
       5:  
       6: import org.apache.commons.pool.ObjectPool;
       7: import org.apache.commons.pool.PoolableObjectFactory;
       8: import org.apache.commons.pool.impl.StackObjectPool;
       9:  
      10:  
      11: /**
      12:  * @author Administrator
      13:  *
      14:  */
      15: public class PoolTest {
      16:  
      17:     /**
      18:      * @param args
      19:      */
      20:     public static void main(String[] args) {
      21:         // TODO Auto-generated method stub
      22:         BigObject bo = null;
      23:         PoolableObjectFactory factory = new TestFactory();
      24:         ObjectPool pool = new StackObjectPool(factory);
      25:         try {
      26:             for(long i = 0; i < 10 ; i++) {
      27:                 System.out.println("== " + i + " ==");
      28:                 bo = (BigObject) pool.borrowObject();
      29:                 System.out.println(bo);
      30:                 System.out.println(pool.getNumActive());
      31:                 if((i&1)==0) {
      32:                     pool.returnObject(bo);
      33:                 }
      34:             }
      35:            // bo = null;//明確地設為null,作為對象已歸還的標志
      36:         }
      37:         catch (Exception e) {
      38:             e.printStackTrace();
      39:         }
      40:         finally {
      41:             try{
      42:                 if (bo != null) {//避免將一個對象歸還兩次
      43:                     pool.returnObject(bo);
      44:                 }
      45:                 pool.close();
      46:             }
      47:             catch (Exception e){
      48:                 e.printStackTrace();
      49:             }
      50:         }
      51:  
      52:     }
      53:  
      54: }
      55:  

    結束了,一個pool的簡單應用就搞定了。下面我們看看代碼的具體實現是什么。

    先看看pool構造時候都做了些什么:

    StackObjectPool里有兩個protected field,一個protected PoolableObjectFactory _factory = null;一個protected Stack _pool = null;。前者是通過構造方法注入的一個factory,我們的代碼里已經自己實現了一個TestFactory;后者是具體的Pool管理策略,像StackObjectPool的話就是內部用這樣一個Stack來管理對象。

    構造時會通過

       1: public StackObjectPool(PoolableObjectFactory factory, int maxIdle, int initIdleCapacity) {
       2:         _factory = factory;
       3:         _maxSleeping = (maxIdle < 0 ? DEFAULT_MAX_SLEEPING : maxIdle);
       4:         int initcapacity = (initIdleCapacity < 1 ? DEFAULT_INIT_SLEEPING_CAPACITY : initIdleCapacity);
       5:         _pool = new Stack();
       6:         _pool.ensureCapacity( initcapacity > _maxSleeping ? _maxSleeping : initcapacity);
       7:     }

    來完成初始參數和變量的構造。

    接著我們開始從pool中取對象了,調用borrowObject的方法,具體實現在源碼中是這樣的:

       1: public synchronized Object borrowObject() throws Exception {
       2:         assertOpen();
       3:         Object obj = null;
       4:         boolean newlyCreated = false;
       5:         while (null == obj) {
       6:             if (!_pool.empty()) {
       7:                 obj = _pool.pop();
       8:             } else {
       9:                 if(null == _factory) {
      10:                     throw new NoSuchElementException();
      11:                 } else {
      12:                     obj = _factory.makeObject();
      13:                     newlyCreated = true;
      14:                   if (obj == null) {
      15:                     throw new NoSuchElementException("PoolableObjectFactory.makeObject() returned null.");
      16:                   }
      17:                 }
      18:             }
      19:             if (null != _factory && null != obj) {
      20:                 try {
      21:                     _factory.activateObject(obj);
      22:                     if (!_factory.validateObject(obj)) {
      23:                         throw new Exception("ValidateObject failed");
      24:                     }
      25:                 } catch (Throwable t) {
      26:                     try {
      27:                         _factory.destroyObject(obj);
      28:                     } catch (Throwable t2) {
      29:                         // swallowed
      30:                     } finally {
      31:                         obj = null;
      32:                     } 
      33:                     if (newlyCreated) {
      34:                         throw new NoSuchElementException(
      35:                             "Could not create a validated object, cause: " +
      36:                             t.getMessage());
      37:                     }
      38:                 }
      39:             }
      40:         }
      41:         _numActive++;
      42:         return obj;
      43:     }

    在不考慮同步的時候,我們只看對象的創建,典型的幾個if邏輯就完成了這樣的功能,在pool空時,就用factory的makeObject方法,不空則直接從內置stack里pop一個對象出來。接著在對象構造OK后,開始激活這個對象。接著調用validate去校驗,如果不合格就跑出異常,而異常的捕獲中又會嘗試去destroy對象,再有問題的話只有swallow掉異常了。整個pool會有一個_numActive變量來控制活著(被borrow但沒被return)的對象數,每次borrow后都會加一。而循環是到obj不空時才退出的,所以obj不會為null。所以,只要你的makeObject合理的不返回null,那么這個邏輯就不會死循環。當然整個過程中似乎都會有多線程安全問題,所以整個方法都加同步。但是這顯然不是完美的解決方法,對于復雜的多線程問題,調度還需要程序員自己來控制。

    接著就是returnObject了,顧名思義就是把從pool中借出來的object還回去。邏輯代碼如下:

       1: public synchronized void returnObject(Object obj) throws Exception {
       2:         boolean success = !isClosed();
       3:         if(null != _factory) {
       4:             if(!_factory.validateObject(obj)) {
       5:                 success = false;
       6:             } else {
       7:                 try {
       8:                     _factory.passivateObject(obj);
       9:                 } catch(Exception e) {
      10:                     success = false;
      11:                 }
      12:             }
      13:         }
      14:  
      15:         boolean shouldDestroy = !success;
      16:  
      17:         _numActive--;
      18:         if (success) {
      19:             Object toBeDestroyed = null;
      20:             if(_pool.size() >= _maxSleeping) {
      21:                 shouldDestroy = true;
      22:                 toBeDestroyed = _pool.remove(0); // remove the stalest object
      23:             }
      24:             _pool.push(obj);
      25:             obj = toBeDestroyed; // swap returned obj with the stalest one so it can be destroyed
      26:         }
      27:         notifyAll(); // _numActive has changed
      28:  
      29:         if(shouldDestroy) { // by constructor, shouldDestroy is false when _factory is null
      30:             try {
      31:                 _factory.destroyObject(obj);
      32:             } catch(Exception e) {
      33:                 // ignored
      34:             }
      35:         }
      36:     }

    首先一個success變量作為判斷位來決定對象能否放回pool。如果經過validate后發現對象不合格,那么顯然不能放回pool了。如果validate合格,那么就嘗試用factory的passivateObject方法使對象變為not active。接著進入邏輯判斷如果可以放回,那么嘗試將對象push到pool的內置stack中,嘗試時會有閾值限定,如果超過了閾值的話,那么需要以某種策略將stack中的對象remove掉一個。而策略如果仔細看代碼就會發現很合理,首先在stack中remove最老的一個,然后將這個remove值保存為臨時變量,將待放回對象push到stack,接著將臨時對象轉接到帶放回對象上。我們看到,這樣的一組行為保證了幾個對象的銷毀,而不會出現內存泄露。

    最后附上apache官網上的幾張時序圖來完美解釋borrow和return的過程:

    clip_image002[4]

    clip_image002[6]

    基本介紹到此,后續可能有進階研究,期待時間~~

    參考資料:

    http://www.ibm.com/developerworks/cn/java/l-common-pool/

    http://commons.apache.org/pool

    posted on 2011-05-06 10:53 changedi 閱讀(6157) 評論(6)  編輯  收藏 所屬分類: Java技術

    評論

    # re: commons-pool學習筆記 2011-05-14 11:19 文學社

    這種結構不錯。  回復  更多評論   

    # re: commons-pool學習筆記[未登錄] 2011-11-09 22:08 刺猬

    我大致瀏覽了下代碼,有兩個問題求解釋:
    1、在判斷idlemax時候,如果到達閾值,remove的是棧底元素,Java stack使用vector實現的,如果remove數組的第一個元素,恐怕在一些vector size比較大情況下性能堪憂,再者,stack里面保留的都是idle狀態的元素,取處于idle最長的意義進行刪除何在? 這又不是LRU
    2、notifyAll 意義? 這個是通知誰 ?   回復  更多評論   

    # re: commons-pool學習筆記[未登錄] 2011-11-10 13:54 changedi

    @刺猬
    1.我想性能問題不算是個問題,這種池結構的設計,只要是這種線性表結構,都難免不了一次remove的數組拷貝,不過一般對象池的維護,大小是自己定的~~肯定不會太大,為了復用,否則new新的對象,交給JVM管理也就是了。
    2.這個問題可以寫個多線程測試的例子,其中同步使用對象鎖,鎖對象就是每個線程應該持有的這個公有的pool。這樣,每次調用pool.wait()就可以讓線程hold等待,在條件滿足時調用一次pool.returnObject(),這樣的notifyAll被調用,一切就都正常了~~
    愚見,歡迎討論  回復  更多評論   

    # re: commons-pool學習筆記[未登錄] 2011-11-10 23:34 刺猬

    謝謝博主答復
    這兩點我是這么看的
    1、其實我從開始就覺得這個類比較雞肋,沒啥大用處。對于這個vector的使用我還是保留意見,認為沒有必要使用,一則清除老idle對象沒有理論依據(或者是至少我沒想到有這種理論依據),二則這里又使用的是vector,如果一定要清楚老對象,完全可以使用linklist之類,在刪除對象可以到O(1)時間復雜度。退者說,沒有實際應用說明我們的對象池對象不會很多,如果我要維持一個size為32的數據庫連接池,對于一些高并發的數據庫請求,會不會出現頻繁的對象新建和釋放。
    2、我贊成博主這個說法,我最初也是這樣猜想,但是如果繼續深挖下去,這個說法同樣困惑:notify的方法不止出現在對象歸還邏輯中,在invalidate對象時同樣會notify操作。Pool調用wait無非是獲取空閑對象發現pool里面沒有空閑對象,釋放Pool鎖進行等待出現空閑對象。那invalidate對象又是通知什么? 再者說,為什么調用Pool的客戶端需要自己控制Pool內部對象的同步互斥——這些本應該直接封裝在borrow方法中的邏輯。從設計上說令人疑惑。
    以前做C的 Java 才入門 有些問題說的不是很清楚 博主見諒   回復  更多評論   

    # re: commons-pool學習筆記[未登錄] 2011-11-11 14:15 changedi

    @刺猬
    深有同感,針對這個同步的問題,其實回答你的時候就發現它惡心了,你說的很對,要么完全交給調用者管理,要么就完全自己管理,這樣半拿半放的讓人困惑~不過代碼簡單,而且又是比較老的東西,能吸收多少就看大家自己了~畢竟是commons下的,可惜了  回復  更多評論   

    # re: commons-pool學習筆記[未登錄] 2011-11-11 23:08 刺猬

    謝謝博主的答復
    回頭看了下genericpool,這個代碼質量好多了  回復  更多評論   

    主站蜘蛛池模板: 亚洲精品视频在线免费| 日韩一级免费视频| 亚洲一卡2卡4卡5卡6卡在线99| 欧洲黑大粗无码免费| 国产亚洲Av综合人人澡精品| 亚洲国产无套无码av电影| 国产1000部成人免费视频| 国产精品成人亚洲| 久久久久亚洲Av片无码v| 四虎在线视频免费观看| 中文在线免费视频| 亚洲色欲色欱wwW在线| 亚洲色偷偷偷鲁综合| 免费看片免费播放| 国产99视频精品免费专区| 亚洲欧美日本韩国| 久久亚洲国产视频| 啊灬啊灬别停啊灬用力啊免费看| 久久久久久一品道精品免费看| 黄页视频在线观看免费| 亚洲明星合成图综合区在线| 亚洲精品无码专区2| 91视频国产免费| 黄网站色视频免费在线观看的a站最新| 亚洲精品美女久久7777777| 久久精品亚洲综合专区| 国产在线a不卡免费视频| 午夜福利不卡片在线播放免费| 三级黄色片免费看| 亚洲av永久无码| 亚洲国产成+人+综合| 亚洲av最新在线网址| 免费成人午夜视频| 成年性午夜免费视频网站不卡 | 最近2019免费中文字幕6| 视频一区在线免费观看| 亚洲看片无码在线视频| 亚洲中文无码av永久| 亚洲成人中文字幕| 亚洲线精品一区二区三区影音先锋| 日美韩电影免费看|