• <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++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            1 對(duì)象池技術(shù)的原理:

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

            2 研究 Apache common pool  

               對(duì)象池結(jié)構(gòu): 

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






            common-dbcp的結(jié)構(gòu)
                apache的連接池工具庫(kù)common-dbcp是common-pool在數(shù)據(jù)庫(kù)訪問(wèn)方面的一個(gè)具體應(yīng)用.當(dāng)對(duì)common-pool熟悉之后, 對(duì)common-dbcp就很好理解了. 它通過(guò)對(duì)已有的Connection, Statment對(duì)象包裝成池對(duì)象PoolableConnection, PoolablePreparedStatement. 然后在這些池化的對(duì)象中, 持有一個(gè)對(duì)對(duì)象池的引用, 在關(guān)閉的時(shí)候, 不進(jìn)行真正的關(guān)閉處理, 而是通過(guò)調(diào)用:
            1. _pool.returnObject(this); 
            或:
            1. _pool.returnObject(_key,this); 
            這樣一句, 將連接對(duì)象放回連接池中.
            而對(duì)應(yīng)的對(duì)象池前者采用的是ObjectPool, 后者是KeyedObjectPool, 因?yàn)橐粋€(gè)數(shù)據(jù)庫(kù)只對(duì)應(yīng)一個(gè)連接, 而執(zhí)行操作的Statement卻根據(jù)Sql的不同會(huì)分很多種. 因此需要根據(jù)sql語(yǔ)句的不同多次進(jìn)行緩存
            在對(duì)連接池的管理上, common-dbcp主要采用兩種對(duì)象:
            一個(gè)是PoolingDriver, 另一個(gè)是PoolingDataSource, 二者的區(qū)別是PoolingDriver是一個(gè)更底層的操作類(lèi), 它持有一個(gè)連接池映射列表, 一般針對(duì)在一個(gè)jvm中要連接多個(gè)數(shù)據(jù)庫(kù), 而后者相對(duì)簡(jiǎn)單一些. 內(nèi)部只能持有一個(gè)連接池, 即一個(gè)數(shù)據(jù)源對(duì)應(yīng)一個(gè)連接池.
            下面是common-dbcp的結(jié)構(gòu)關(guān)系:


            下面是參考了common-dbcp的例子之后寫(xiě)的一個(gè)從連接池中獲取連接的工具類(lèi)

            1. /**
            2. * 創(chuàng)建連接
            3. *
            4. * @since 2009-1-22 下午02:58:35
            5. */
            6. public class ConnectionUtils {
            7. // 一些common-dbcp內(nèi)部定義的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. * 取得池化驅(qū)動(dòng)器
            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. * 銷(xiāo)毀所有連接
            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. * 從連接池中獲取數(shù)據(jù)庫(kù)連接
            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. // 這里找不到連接池會(huì)拋異常, 需要catch一下
            48. try {
            49. pool = driver.getConnectionPool(key);
            50. } catch (Exception e) {
            51. }
            52.
            53. if (pool == null) {
            54. // 根據(jù)數(shù)據(jù)庫(kù)類(lèi)型構(gòu)建連接工廠
            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. // 構(gòu)造連接池
            68. ObjectPool connectionPool = new GenericObjectPool(null);
            69. new PoolableConnectionFactory(connectionFactory, connectionPool,
            70. null, null, false, true);
            71.
            72. // 將連接池注冊(cè)到driver中
            73. driver.registerPool(key, connectionPool);
            74. }
            75.
            76. // 從連接池中拿一個(gè)連接
            77. return DriverManager.getConnection(POOL_DRIVER_KEY + key);
            78. }
            79.
            80. }


            雖然對(duì)象池技術(shù)在實(shí)際開(kāi)發(fā)過(guò)程中用的不是很多, 但是理解之后對(duì)我們寫(xiě)程序還是有莫大的好處的, 至少我是這樣的

            3 用法:

                 dbcp([url]http://jakarta.apache.org/commons/dbcp/[/url])這個(gè)apache的開(kāi)源的數(shù)據(jù)庫(kù)連接池。結(jié)果發(fā)現(xiàn)dbcp依賴(lài)Apache common pool([url]http://jakarta.apache.org/commons/pool/[/url]


            關(guān)于對(duì)象池更多具體用法:

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

            老男人久久青草av高清| 久久中文字幕无码专区| 久久久久无码国产精品不卡| 国产成人无码久久久精品一| 亚洲精品NV久久久久久久久久| 国产成人久久777777| 国产一级持黄大片99久久| 99久久夜色精品国产网站| 久久久黄色大片| 久久久国产99久久国产一| 久久久精品久久久久久 | 亚洲综合日韩久久成人AV| 亚洲美日韩Av中文字幕无码久久久妻妇 | 青青草原1769久久免费播放| 久久婷婷五月综合97色| 日韩精品久久久久久免费| 久久99精品久久只有精品| 久久国产精品成人片免费| av无码久久久久久不卡网站| 国产成人久久激情91| 香蕉久久一区二区不卡无毒影院| 999久久久国产精品| 久久亚洲中文字幕精品一区| 亚洲Av无码国产情品久久| 久久笫一福利免费导航| 99精品久久久久久久婷婷| 久久久久久久久久久久中文字幕 | 久久久久久久久66精品片| 国产成人无码精品久久久性色| 久久99久久99精品免视看动漫| 久久水蜜桃亚洲av无码精品麻豆| 久久99精品国产麻豆宅宅| 久久久国产精华液| 久久人人爽人人爽人人片AV不 | 色综合久久中文色婷婷| 久久久久国产精品麻豆AR影院| 欧美国产成人久久精品| 成人国内精品久久久久一区| 久久强奷乱码老熟女网站| 亚洲综合精品香蕉久久网| 亚洲伊人久久大香线蕉苏妲己|