對象池

    單例模式是限制了一個類只能有一個實例,對象池模式則是限制一個類實例的個數。對象池類就像是一個對象管理員,它以Static列表(也就是裝對象的池子)的形式存存儲某個實例數受限的類的實例,每個實例還要加一個標記,標記該實例是否被佔用。當類初始化的時候,這個對象池就被初始化了,實例就被建立出來。而後,用戶能夠向這個類索取實例,若是池中全部的實例都已經被佔用了,那麼拋出異常。用戶用完之後,還要把實例「還」回來,即釋放佔用。對象池類的成員應該都是靜態的。用戶也不該該能訪問池子裏裝着的對象的構造函數,以防用戶繞開對象池建立實例。書上說這個模式會用在數據庫鏈接的管理上。好比,每一個用戶的鏈接數是有限的,這樣每一個鏈接就是一個池子裏的一個對象,「鏈接池」類就能夠控制鏈接數了。java

Java對象的生命週期分析

  Java對象的生命週期大體包括三個階段:對象的建立,對象的使用,對象的清除。所以,對象的生命週期長度可用以下的表達式表示:T = T1 + T2 +T3。其中T1表示對象的建立時間,T2表示對象的使用時間,而T3則表示其清除時間。由此,咱們能夠看出,只有T2是真正有效的時間,而T一、T3則是對象自己的開銷。下面再看看T一、T3在對象的整個生命週期中所佔的比例。

  咱們知道,Java對象是經過構造函數來建立的,在這一過程當中,該構造函數鏈中的全部構造函數也都會被自動調用。另外,默認狀況下,調用類的構造函數時,Java會把變量初始化成肯定的值:全部的對象被設置成null,整數變量(byte、short、int、long)設置成0,float和double變量設置成0.0,邏輯值設置成false。因此用new關鍵字來新建一個對象的時間開銷是很大的,如表1所示。

  表1 一些操做所耗費時間的對照表程序員

運算操做數據庫

示例apache

標準化時間數組

本地賦值緩存

i = n函數

1.0性能

實例賦值測試

this.i = nthis

1.2

方法調用

Funct()

5.9

新建對象

New Object()

980

新建數組

New int[10]

3100


  從表1能夠看出,新建一個對象須要980個單位的時間,是本地賦值時間的980倍,是方法調用時間的166倍,而若新建一個數組所花費的時間就更多了。

  再看清除對象的過程。咱們知道,Java語言的一個優點,就是Java程序員勿需再像C/C++程序員那樣,顯式地釋放對象,而由稱爲垃圾收集器(Garbage Collector)的自動內存管理系統,定時或在內存凸現出不足時,自動回收垃圾對象所佔的內存。凡事有利總也有弊,這雖然爲Java程序設計者提供了極大的方便,但同時它也帶來了較大的性能開銷。這種開銷包括兩方面,首先是對象管理開銷,GC爲了可以正確釋放對象,它必須監控每個對象的運行狀態,包括對象的申請、引用、被引用、賦值等。其次,在GC開始回收「垃圾」對象時,系統會暫停應用程序的執行,而獨自佔用CPU。

  所以,若是要改善應用程序的性能,一方面應儘可能減小建立新對象的次數;同時,還應儘可能減小T一、T3的時間,而這些都可以經過對象池技術來實現。

  對象池技術的基本原理

  對象池技術基本原理的核心有兩點:緩存和共享,即對於那些被頻繁使用的對象,在使用完後,不當即將它們釋放,而是將它們緩存起來,以供後續的應用程序重複使用,從而減小建立對象和釋放對象的次數,進而改善應用程序的性能。事實上,因爲對象池技術將對象限制在必定的數量,也有效地減小了應用程序內存上的開銷。

對象池使用的基本思路是:

將用過的對象保存起來,等下一次須要這種對象的時候,再拿出來重複使用,從而在必定程度上減小頻繁建立對象所形成的開銷。 並不是全部對象都適合拿來池化――由於維護對象池也要形成必定開銷。對生成時開銷不大的對象進行池化,反而可能會出現「維護對象池的開銷」大於「生成新對象的開銷」,從而使性能下降的狀況。可是對於生成時開銷可觀的對象,池化技術就是提升性能的有效策略了。下面是構建對象池的一個例子:

[java] view plain copy
  1. public class ObjectPool {       
  2.     private int numObjects = 10; // 對象池的大小       
  3.     private int maxObjects = 50; // 對象池最大的大小       
  4.     private Vector objects = null; //存放對象池中對象的向量( PooledObject類型)         
  5.     
  6.     public ObjectPool() {              
  7.     }       
  8.       
  9.     /*** 建立一個對象池***/       
  10.     public synchronized void createPool(){       
  11.         // 確保對象池沒有建立。若是建立了,保存對象的向量 objects 不會爲空       
  12.         if (objects != null) {       
  13.             return; // 若是己經建立,則返回       
  14.         }       
  15.       
  16.         // 建立保存對象的向量 , 初始時有 0 個元素       
  17.         objects = new Vector();       
  18.       
  19.         // 根據 numObjects 中設置的值,循環建立指定數目的對象       
  20.         for (int x = 0; x < numObjects; x++) {       
  21.            if ((objects.size() == 0)&&this.objects.size() <this.maxObjects) {    
  22.               Object obj = new Obj();       
  23.               objects.addElement(new PooledObject(obj));                 
  24.       }  
  25.     }  
  26.     }       
  27.       
  28.     public synchronized Object getObject(){       
  29.         // 確保對象池己被建立       
  30.         if (objects == null) {       
  31.             return null; // 對象池還沒建立,則返回 null       
  32.         }       
  33.       
  34.         Object conn = getFreeObject(); // 得到一個可用的對象       
  35.       
  36.         // 若是目前沒有可使用的對象,即全部的對象都在使用中       
  37.         while (conn == null) {       
  38.             wait(250);       
  39.             conn = getFreeObject(); // 從新再試,直到得到可用的對象,若是       
  40.             // getFreeObject() 返回的爲 null,則代表建立一批對象後也不可得到可用對象       
  41.         }       
  42.       
  43.         return conn;// 返回得到的可用的對象       
  44.     }       
  45.       
  46.     /**    
  47.      * 本函數從對象池對象 objects 中返回一個可用的的對象,若是    
  48.      * 當前沒有可用的對象,則建立幾個對象,並放入對象池中。    
  49.      * 若是建立後,全部的對象都在使用中,則返回 null    
  50.      */      
  51.     private Object getFreeObject(){       
  52.       
  53.         // 從對象池中得到一個可用的對象       
  54.         Object obj = findFreeObject();       
  55.       
  56.         if (obj == null) {       
  57.             createObjects(incrementalObjects);     //若是目前對象池中沒有可用的對象,建立一些對象       
  58.   
  59.             // 從新從池中查找是否有可用對象       
  60.             obj = findFreeObject();       
  61.                      
  62.            // 若是建立對象後仍得到不到可用的對象,則返回 null       
  63.             if (obj == null) {       
  64.                 return null;       
  65.             }       
  66.         }       
  67.       
  68.         return obj;       
  69.     }       
  70.       
  71.     /**    
  72.      * 查找對象池中全部的對象,查找一個可用的對象,    
  73.      * 若是沒有可用的對象,返回 null    
  74.      */      
  75.     private Object findFreeObject(){       
  76.       
  77.         Object obj = null;       
  78.         PooledObject pObj = null;       
  79.       
  80.         // 得到對象池向量中全部的對象       
  81.         Enumeration enumerate = objects.elements();       
  82.       
  83.         // 遍歷全部的對象,看是否有可用的對象       
  84.         while (enumerate.hasMoreElements()) {       
  85.             pObj = (PooledObject) enumerate.nextElement();       
  86.                       
  87.            // 若是此對象不忙,則得到它的對象並把它設爲忙       
  88.             if (!pObj.isBusy()) {       
  89.                 obj = pObj.getObject();       
  90.                 pObj.setBusy(true);       
  91.            }  
  92.      
  93.         return obj;// 返回找到到的可用對象       
  94.     }       
  95.       
  96.       
  97.     /**    
  98.      * 此函數返回一個對象到對象池中,並把此對象置爲空閒。    
  99.      * 全部使用對象池得到的對象均應在不使用此對象時返回它。    
  100.      */      
  101.       
  102.     public void returnObject(Object obj) {       
  103.       
  104.         // 確保對象池存在,若是對象沒有建立(不存在),直接返回       
  105.         if (objects == null) {       
  106.             return;       
  107.         }       
  108.       
  109.         PooledObject pObj = null;       
  110.       
  111.         Enumeration enumerate = objects.elements();       
  112.       
  113.         // 遍歷對象池中的全部對象,找到這個要返回的對象對象       
  114.         while (enumerate.hasMoreElements()) {       
  115.             pObj = (PooledObject) enumerate.nextElement();       
  116.   
  117.             // 先找到對象池中的要返回的對象對象       
  118.             if (obj == pObj.getObject()) {       
  119.                 // 找到了 , 設置此對象爲空閒狀態       
  120.                 pObj.setBusy(false);       
  121.                 break;       
  122.             }       
  123.         }       
  124.     }       
  125.       
  126.       
  127.     /**    
  128.      * 關閉對象池中全部的對象,並清空對象池。    
  129.      */      
  130.     public synchronized void closeObjectPool() {       
  131.       
  132.         // 確保對象池存在,若是不存在,返回       
  133.         if (objects == null) {       
  134.             return;       
  135.         }       
  136.       
  137.         PooledObject pObj = null;       
  138.       
  139.         Enumeration enumerate = objects.elements();       
  140.       
  141.         while (enumerate.hasMoreElements()) {       
  142.       
  143.             pObj = (PooledObject) enumerate.nextElement();       
  144.       
  145.             // 若是忙,等 5 秒       
  146.             if (pObj.isBusy()) {       
  147.                 wait(5000); // 等 5 秒       
  148.             }       
  149.       
  150.             // 從對象池向量中刪除它       
  151.             objects.removeElement(pObj);       
  152.         }       
  153.       
  154.         // 置對象池爲空       
  155.         objects = null;       
  156.     }       
  157.       
  158.       
  159.     /**    
  160.      * 使程序等待給定的毫秒數    
  161.      */      
  162.     private void wait(int mSeconds) {       
  163.         try {       
  164.             Thread.sleep(mSeconds);       
  165.         }  
  166.        catch (InterruptedException e) {       
  167.         }       
  168.     }       
  169.       
  170.      
  171.     /**    
  172.      * 內部使用的用於保存對象池中對象的類。    
  173.      * 此類中有兩個成員,一個是對象,另外一個是指示此對象是否正在使用的標誌 。 
  174.      */      
  175.     class PooledObject {       
  176.       
  177.         Object objection = null;// 對象       
  178.         boolean busy = false; // 此對象是否正在使用的標誌,默認沒有正在使用       
  179.       
  180.         // 構造函數,根據一個 Object 構告一個 PooledObject 對象       
  181.         public PooledObject(Object objection) {       
  182.       
  183.             this.objection = objection;       
  184.       
  185.         }       
  186.       
  187.         // 返回此對象中的對象       
  188.         public Object getObject() {       
  189.             return objection;       
  190.         }       
  191.       
  192.         // 設置此對象的,對象       
  193.         public void setObject(Object objection) {       
  194.             this.objection = objection;       
  195.       
  196.         }       
  197.       
  198.         // 得到對象對象是否忙       
  199.         public boolean isBusy() {       
  200.             return busy;       
  201.         }       
  202.       
  203.         // 設置對象的對象正在忙       
  204.         public void setBusy(boolean busy) {       
  205.             this.busy = busy;       
  206.         }       
  207.     }       
  208. }      
  209.    
  210.    
  211. 測試類:  
  212. 代碼以下:  
  213.       
  214. public class ObjectPoolTest {       
  215.     public static void main(String[] args) throws Exception {       
  216.         ObjectPool objPool = new ObjectPool();  
  217.       
  218.         objPool.createPool();       
  219.         Object obj = objPool.getObject();       
  220.         returnObject(obj);  
  221.         objPool.closeObjectPool();       
  222.     }       
  223. }  

commons-pool提供了一套很好用的對象池組件。使用也很簡單,不過對一些簡單的對象使用對象池就不必了。

ObjectPool定義了一個簡單的池化接口,有三個對應實現
GenericObjectPool:實現了可配置的後進先出或先進先出(LIFO/FIFO)行爲,默認是做爲一個後進先出隊列,這意味當對象池中有可用的空閒對象時,borrowObject 將返回最近的對象實例,若是將lifo 屬性設置爲false,則按FIFO行爲返回對象實例。
StackObjectPool :實現了後進先出(LIFO)行爲。
SoftReferenceObjectPool: 實現了後進先出(LIFO)行爲。另外,對象池還在SoftReference 中保存了每一個對象引用,容許垃圾收集器針對內存須要回收對象。

KeyedObjectPool定義了一個以任意的key訪問對象的接口(能夠池化對種對象),有兩種對應實現。
GenericKeyedObjectPool :實現了先進先出(FIFO)行爲。
StackKeyedObjectPool : 實現了後進先出(LIFO)行爲。

PoolableObjectFactory 定義了池化對象的生命週期方法,咱們可使用它分離被池化的不一樣對象和管理對象的建立,持久,銷燬。
BasePoolableObjectFactory這個實現PoolableObjectFactory 接口的一個抽象類,咱們可用擴展它實現本身的池化工廠。

一個對象池使用的簡單例子:

[java] view plain copy
    1. package tf;  
    2.   
    3. import org.apache.commons.pool.BasePoolableObjectFactory;  
    4. import org.apache.commons.pool.ObjectPool;  
    5. import org.apache.commons.pool.impl.StackObjectPool;  
    6.   
    7. public class Pool {  
    8.   
    9.     public static void main(String[] args) throws Exception {  
    10.         ObjectPool pool = new StackObjectPool(new UserFactory());  
    11.         User u = (User) pool.borrowObject(); // 從池中借出一個對象  
    12.         u.setName("me");  
    13.         u.sayHello();  
    14.         pool.returnObject(u); // 歸還對象  
    15.     }  
    16.   
    17.     static class UserFactory extends BasePoolableObjectFactory {  
    18.         /** 
    19.          * 產生一個新對象 
    20.          */  
    21.         public Object makeObject() {  
    22.             return new User();  
    23.         }  
    24.   
    25.         /** 
    26.          * 還原對象狀態 
    27.          */  
    28.         public void passivateObject(Object obj) {  
    29.             User u = (User) obj;  
    30.             u.clear();  
    31.         }  
    32.     }  
    33.   
    34.     static class User {  
    35.         String name;  
    36.   
    37.         void setName(String name) {  
    38.             this.name = name;  
    39.         }  
    40.   
    41.         void sayHello() {  
    42.             System.out.println("hello, " + name);  
    43.         }  
    44.   
    45.         void clear() {  
    46.             name = "";  
    47.         }  
    48.     }  
相關文章
相關標籤/搜索