• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 311, comments - 0, trackbacks - 0, articles - 0
              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

            (搬運工)對象池技術

            Posted on 2011-04-29 14:39 點點滴滴 閱讀(628) 評論(0)  編輯 收藏 引用

            1 對象池技術的原理:

                對象池技術在服務器開發上應用廣泛。在各種對象池的實現中,尤其以數據庫的連接池最為明顯,可以說是每個服務器必須實現的部分。本文是個人學習對象池的一個記錄,以Apache的commons-pool實現為研究對象。在第二部分中,本人將繼續研究Apache的common-dbcp,這是對象池技術在JDBC上的一個應用范例。
                ObjectPool維護一個列表,其中存放所有已經生成的對象。同時導出幾個方法,如 borrowObject,returnObject,addObject等等。當用戶調用borrowObject時,ObjectPool查看當前列表中的空閑對象的數目,如果有空閑的對象,則初始化該對象后返回給用戶,否則創建一個對象,返回給用戶使用。同理,當用戶調用returnObject 時,ObjectPool查看當前隊列中的空閑對象數目,如果數目小于DEFAULT_MAX_SLEEPING,則將改對象的狀態清空,然后放到隊列中,作為備用對象;否則直接銷毀該對象。
                對象池中還涉及到一些高級的技術, 比如過期銷毀, 被破壞時銷毀, 對象數超過池大小銷毀, 對象池中沒有可用空閑對象時等待等等.
            apache的common-pool工具庫是對池化技術原理的一種具體實現. 在闡述原理之前, 這里先理解幾個概念:
            對象池(ObjectPool接口): 可以把它認為是一種容器, 它是用來裝池對象的, 并且包含了用來創建池對象的工廠對象
            池對象:就是要放到池容器中的對象, 理論上可以是任何對象.
            對象池工廠(ObjectPoolFactory接口):用來創建對象池的工廠, 這個沒什么好說的.
            池對象工廠(PoolableObjectFactory 接口):用來創建池對象, 將不用的池對象進行鈍化(passivateObject), 對要使用的池對象進行激活(activeObject), 對池對象進行驗證(validateObject), 對有問題的池對象進行銷毀(destroyObject)等工作
                對象池中封裝了創建, 獲取, 歸還, 銷毀池對象的職責, 當然這些工作都是通過池對象工廠來實施的, 容器內部還有一個或多個用來盛池對象的容器.對象池會對容器大小, 存放時間, 訪問等待時間, 空閑時間等等進行一些控制, 因為可以根據需要來調整這些設置.
                當需要拿一個池對象的時候, 就從容器中取出一個, 如果容器中沒有的話, 而且又沒有達到容器的最大限制, 那么就調用池對象工廠, 新建一個池對象, 并調用工廠的激活方法, 對創建的對象進行激活, 驗證等一系列操作. 如果已經達到池容器的最大值, 而對象池中又經沒有空閑的對象, 那么將會繼續等待, 直到有新的空閑的對象被丟進來, 當然這個等待也是有限度的, 如果超出了這個限度, 對象池就會拋出異常.
                “出來混, 總是要還的”, 池對象也是如此, 當將用完的池對象歸還到對象池中的時候, 對象池會調用池對象工廠對該池對象進行驗證, 如果驗證不通過則被認為是有問題的對象, 將會被銷毀, 同樣如果容器已經滿了, 這個歸還池對象將變的”無家可歸”, 也會被銷毀, 如果不屬于上面兩種情況, 對象池就會調用工廠對象將其鈍化并放入容器中. 在整個過程中, 激活, 檢查, 鈍化處理都不是必須的, 因此我們在實PoolableObjectFactory接口的時候, 一般不作處理, 給空實現即可, 所以誕生了BasePoolableObjectFactory.
                當然你也可以將要已有的對象創建好, 然后通過addObject放到對象池中去, 以備后用.
                為了確保對對象池的訪問都是線程安全的, 所有對容器的操作都必須放在synchronized中.
                這種備用的觀念正是對象池的理論基礎,可以很大程度上減少對象生成和銷毀的次數。對于那些初始化過程很慢的對象來說,減少對象構造和銷毀的次數就等于大幅度提高了整體效率。特別是對于數據庫連接這樣的對象,由于進行JNDI搜索的效率極為低下,應用對象池技術是理所當然的。
                需要注意的是,對象池技術并不是對任何對象都適用。因為對象池本身的操作要耗費一些資源,對于一些小對象來說,使用對象池可能取得相反的效果。IBM DeveloperWorks上有一篇論文,指出簡單對象如Point,Size等,使用對象池技術并不能帶來性能的改善;而復雜對象如 JPanel,JFrame等,使用對象池后能帶來稍微的性能優勢;最最適合對象池技術的是一些耗時操作,如JDBC連接,線程等。 

            2 研究 Apache common pool  

               對象池結構: 

               在 apache的common-pool工具庫中有5種對象池:GenericObjectPool和 GenericKeyedObjectPool, SoftReferenceObjectPool, StackObjectPool, StackKeyedObjectPool.
               五種對象池可分為兩類, 一類是無key的(有key的類圖相似):
               
                前面兩種用CursorableLinkedList來做容器
                SoftReferenceObjectPool用ArrayList做容器, 一次性創建所有池化對象, 并對容器中的對象進行了軟引用(SoftReference)處理, 從而保證在內存充足的時候池對象不會輕易被jvm垃圾回收, 從而具有很強的緩存能力.
                最后兩種用Stack做容器. 不帶key的對象池是對前面池技術原理的一種簡單實現, 帶key的相對復雜一些, 它會將池對象按照key來進行分類, 具有相同的key被劃分到一組類別中, 因此有多少個key, 就會有多少個容器. 之所以需要帶key的這種對象池, 是因為普通的對象池通過makeObject()方法創建的對象基本上都是一模一樣的, 因為沒法傳遞參數來對池對象進行定制. 
                因此四種池對象的區別主要體現在內部的容器的區別, Stack遵循”后進先出”的原則并能保證線程安全, CursorableLinkedList是一個內部用游標(cursor)來定位當前元素的雙向鏈表, 是非線程安全的, 但是能滿足對容器的并發修改.ArrayList是非線程安全的, 便利方便的容器.
                
                使用對象池的一般步驟:創建一個池對象工廠, 將該工廠注入到對象池中, 當要取池對象, 調用borrowObject, 當要歸還池對象時, 調用returnObject, 銷毀池對象調用clear(), 如果要連池對象工廠也一起銷毀, 則調用close().
            下面是一些時序圖:






            common-dbcp的結構
                apache的連接池工具庫common-dbcp是common-pool在數據庫訪問方面的一個具體應用.當對common-pool熟悉之后, 對common-dbcp就很好理解了. 它通過對已有的Connection, Statment對象包裝成池對象PoolableConnection, PoolablePreparedStatement. 然后在這些池化的對象中, 持有一個對對象池的引用, 在關閉的時候, 不進行真正的關閉處理, 而是通過調用:
            1. _pool.returnObject(this); 
            或:
            1. _pool.returnObject(_key,this); 
            這樣一句, 將連接對象放回連接池中.
            而對應的對象池前者采用的是ObjectPool, 后者是KeyedObjectPool, 因為一個數據庫只對應一個連接, 而執行操作的Statement卻根據Sql的不同會分很多種. 因此需要根據sql語句的不同多次進行緩存
            在對連接池的管理上, common-dbcp主要采用兩種對象:
            一個是PoolingDriver, 另一個是PoolingDataSource, 二者的區別是PoolingDriver是一個更底層的操作類, 它持有一個連接池映射列表, 一般針對在一個jvm中要連接多個數據庫, 而后者相對簡單一些. 內部只能持有一個連接池, 即一個數據源對應一個連接池.
            下面是common-dbcp的結構關系:


            下面是參考了common-dbcp的例子之后寫的一個從連接池中獲取連接的工具類

            1. /**
            2. * 創建連接
            3. *
            4. * @since 2009-1-22 下午02:58:35
            5. */
            6. public class ConnectionUtils {
            7. // 一些common-dbcp內部定義的protocol
            8. private static final String POOL_DRIVER_KEY = "jdbc:apache:commons:dbcp:";
            9. private static final String POLLING_DRIVER = "org.apache.commons.dbcp.PoolingDriver";
            10.
            11. /**
            12. * 取得池化驅動器
            13. *
            14. * @return
            15. * @throws ClassNotFoundException
            16. * @throws SQLException
            17. */
            18. private static PoolingDriver getPoolDriver() throws ClassNotFoundException,
            19. SQLException {
            20. Class.forName(POLLING_DRIVER);
            21. return (PoolingDriver) DriverManager.getDriver(POOL_DRIVER_KEY);
            22. }
            23.
            24. /**
            25. * 銷毀所有連接
            26. *
            27. * @throws Exception
            28. */
            29. public static void destory() throws Exception {
            30. PoolingDriver driver = getPoolDriver();
            31. String[] names = driver.getPoolNames();
            32. for (String name : names) {
            33. driver.getConnectionPool(name).close();
            34. }
            35. }
            36.
            37. /**
            38. * 從連接池中獲取數據庫連接
            39. */
            40. public static Connection getConnection(TableMetaData table)
            41. throws Exception {
            42. String key = table.getConnectionKey();
            43.
            44. PoolingDriver driver = getPoolDriver();
            45.
            46. ObjectPool pool = null;
            47. // 這里找不到連接池會拋異常, 需要catch一下
            48. try {
            49. pool = driver.getConnectionPool(key);
            50. } catch (Exception e) {
            51. }
            52.
            53. if (pool == null) {
            54. // 根據數據庫類型構建連接工廠
            55. ConnectionFactory connectionFactory = null;
            56. if (table.getDbAddr() != null
            57. && TableMetaData.DB_TYPE_MYSQL == table.getDbType()) {
            58. Class.forName(TableMetaData.MYSQL_DRIVER);
            59. connectionFactory = new DriverManagerConnectionFactory(table
            60. .getDBUrl(), null);
            61. } else {
            62. Class.forName(TableMetaData.ORACLE_DRIVER);
            63. connectionFactory = new DriverManagerConnectionFactory(table
            64. .getDBUrl(), table.getDbuser(), table.getDbpass());
            65. }
            66.
            67. // 構造連接池
            68. ObjectPool connectionPool = new GenericObjectPool(null);
            69. new PoolableConnectionFactory(connectionFactory, connectionPool,
            70. null, null, false, true);
            71.
            72. // 將連接池注冊到driver中
            73. driver.registerPool(key, connectionPool);
            74. }
            75.
            76. // 從連接池中拿一個連接
            77. return DriverManager.getConnection(POOL_DRIVER_KEY + key);
            78. }
            79.
            80. }


            雖然對象池技術在實際開發過程中用的不是很多, 但是理解之后對我們寫程序還是有莫大的好處的, 至少我是這樣的

            3 用法:

                 dbcp([url]http://jakarta.apache.org/commons/dbcp/[/url])這個apache的開源的數據庫連接池。結果發現dbcp依賴Apache common pool([url]http://jakarta.apache.org/commons/pool/[/url]


            關于對象池更多具體用法:

            [url]http://www.ibm.com/developerworks/cn/java/l-common-pool/index.html#4[/url]

            久久免费视频一区| 一本色道久久综合狠狠躁| 久久亚洲国产成人精品性色| 国产精品久久久久久久人人看| 精品国产99久久久久久麻豆| 亚洲国产精品无码久久| 国产精品视频久久| 精品乱码久久久久久夜夜嗨| 久久久久人妻一区精品| 色播久久人人爽人人爽人人片AV| 欧美黑人激情性久久| 国产精品一区二区久久精品无码| 中文成人无码精品久久久不卡| 久久亚洲美女精品国产精品| 99久久免费国产精品| 婷婷久久久亚洲欧洲日产国码AV | 欧美亚洲另类久久综合婷婷| 久久亚洲精品成人无码网站| 久久青青草原综合伊人| 久久99九九国产免费看小说| 91精品国产色综合久久| 人妻系列无码专区久久五月天| 日韩人妻无码精品久久免费一| 久久激情亚洲精品无码?V| 无码人妻久久一区二区三区免费丨 | 久久久久久a亚洲欧洲aⅴ| 久久亚洲国产最新网站| 久久香蕉国产线看观看99| 久久国语露脸国产精品电影| 久久伊人精品青青草原日本| 国产精品九九久久免费视频 | 亚洲七七久久精品中文国产 | 久久夜色精品国产欧美乱| 久久综合欧美成人| 久久精品水蜜桃av综合天堂| 女人高潮久久久叫人喷水| 99久久伊人精品综合观看| 国产精品99久久免费观看| 久久精品中文字幕一区| 亚洲国产成人久久综合区| 久久午夜综合久久|