java 對象池技術

中斷了一段時間,再次開始技術之旅;心里有個小目標,先把對象池技術梳理清楚。


1、為什么用對象池

在 java 中,對象的生命周期包括對象創建、對象使用,對象消失三個時間段,其中對象的使用是對象真正需要存活的時間,不好修改,該用的時候還得使用啊。對象的創建和消失就得好好控制下了。對象的創建是比較費時間的,也許感覺不到,好比一個賦值操作int i=1,也是需要耗時的,在比如構造一個對象,一個數組就更加消耗時間。再說對象的消除,在 java 里面使用 GC 來進行對象回收,其實也是需要對對象監控每一個運行狀態,包括引用,賦值等。在 Full GC 的時候,會暫停其他操作,獨占 CPU。所以,我們需要控制對象的創建數量,也不要輕易的讓對象消失,讓他的復用更加充分。

2、對象池

對象池其實就是一個集合,里面包含了我們需要的對象集合,當然這些對象都被池化了,也就是被對象池所管理,想要這樣的對象,從池子里取個就行,但是用完得歸還。對象池的對象最好是創建比較費時的大對象,如果是太簡單的對象,再進入池化的時間比自己構建還多,就不劃算了。可以理解對象池為單例模式的延展,多例模式,就那么幾個對象實例,再多沒有了。

3、自定義一個低質量的對象池

首先構造一個池化對象,也就是對實際對象封裝下,為什么呢?當然是為了讓對象池更好的管理



public  class PooledObject<T> {

 private T objection = null;// 外界使用的對象
 private boolean busy = false; // 此對象是否正在使用的標志,默認沒有正在使用

 // 構造函數,池化對象
 public PooledObject(T objection) {
  this.objection = objection;
 }

 // 返回此對象中的對象
 public T getObject() {
  return objection;
 }

 // 設置此對象的,對象
 public void setObject(T objection) {
  this.objection = objection;
 }

 // 獲得對象對象是否忙
 public boolean isBusy() {
  return busy;
 }

 // 設置對象的對象正在忙
 public void setBusy(boolean busy) {
  this.busy = busy;
 }
 
 
}

池化對象現在包括兩個屬性,一個是原始對象的引用,另外一個表示當前對象是否在使用

接下來把對象池寫出來


import java.util.Enumeration;
import java.util.Vector;

public abstract class ObjectPool<T> {
    public static int numObjects = 10; // 對象池的大小
    public static int maxObjects = 50; // 對象池最大的大小
    protected Vector<PooledObject<T>> objects = null; // 存放對象池中對象的向量(PooledObject類型)

    public ObjectPool() {
    }

    /*** 創建一個對象池 ***/
    public synchronized void createPool() {
        // 確保對象池沒有創建。如果創建了,保存對象的向量 objects 不會為空
        if (objects != null) {
            return; // 如果己經創建,則返回
        }
        // 創建保存對象的向量 , 初始時有 0 個元素
         objects = new Vector<PooledObject<T>>();
         for (int i = 0; i < numObjects; i++) {
                objects.addElement(create());
            }
    }

    public abstract PooledObject<T> create();

    public synchronized T getObject() {
        // 確保對象池己被創建
        if (objects == null) {
            return null; // 對象池還沒創建,則返回 null
        }
        T t = getFreeObject(); // 獲得一個可用的對象
        // 如果目前沒有可以使用的對象,即所有的對象都在使用中
        while (t == null) {
            wait(250);
            t = getFreeObject(); // 重新再試,直到獲得可用的對象,如果
            // getFreeObject() 返回的為 null,則表明創建一批對象后也不可獲得可用對象
        }
        return t;// 返回獲得的可用的對象
    }

    /**
     * 本函數從對象池對象 objects 中返回一個可用的的對象,如果 當前沒有可用的對象,則創建幾個對象,并放入對象池中。
     * 如果創建后,所有的對象都在使用中,則返回 null
     */
    private T getFreeObject() {
        // 從對象池中獲得一個可用的對象
        T obj = findFreeObject();
        if (obj == null) {
            createObjects(10); // 如果目前對象池中沒有可用的對象,創建一些對象
            // 重新從池中查找是否有可用對象
            obj = findFreeObject();
            // 如果創建對象后仍獲得不到可用的對象,則返回 null
            if (obj == null) {
                return null;
            }
        }
        return obj;
    }

    public void createObjects(int increment){
        for (int i = 0; i < increment; i++) {
            if (objects.size() > maxObjects) {
                return;
            }
            objects.addElement(create());
        }
    }

    /**
     * 查找對象池中所有的對象,查找一個可用的對象, 如果沒有可用的對象,返回 null
     */
    private T findFreeObject() {
        T obj = null;
        PooledObject<T> pObj = null;
        // 獲得對象池向量中所有的對象
        Enumeration<PooledObject<T>> enumerate = objects.elements();
        // 遍歷所有的對象,看是否有可用的對象
        while (enumerate.hasMoreElements()) {
            pObj = (PooledObject<T>) enumerate.nextElement();

            // 如果此對象不忙,則獲得它的對象并把它設為忙
            if (!pObj.isBusy()) {
                obj = pObj.getObject();
                pObj.setBusy(true);
            }
        }
        return obj;// 返回找到到的可用對象
    }

    /**
     * 此函數返回一個對象到對象池中,并把此對象置為空閑。 所有使用對象池獲得的對象均應在不使用此對象時返回它。
     */

    public void returnObject(T obj) {
        // 確保對象池存在,如果對象沒有創建(不存在),直接返回
        if (objects == null) {
            return;
        }
        PooledObject<T> pObj = null;
        Enumeration<PooledObject<T>> enumerate = objects.elements();
        // 遍歷對象池中的所有對象,找到這個要返回的對象對象
        while (enumerate.hasMoreElements()) {
            pObj = (PooledObject<T>) enumerate.nextElement();
            // 先找到對象池中的要返回的對象對象
            if (obj == pObj.getObject()) {
                // 找到了 , 設置此對象為空閑狀態
                pObj.setBusy(false);
                break;
            }
        }
    }

    /**
     * 關閉對象池中所有的對象,并清空對象池。
     */
    public synchronized void closeObjectPool() {
        // 確保對象池存在,如果不存在,返回
        if (objects == null) {
            return;
        }
        PooledObject<T> pObj = null;
        Enumeration<PooledObject<T>> enumerate = objects.elements();
        while (enumerate.hasMoreElements()) {
            pObj = (PooledObject<T>) enumerate.nextElement();
            // 如果忙,等 0.5 秒
            if (pObj.isBusy()) {
                wait(500); // 等
            }
            // 從對象池向量中刪除它
            objects.removeElement(pObj);
        }
        // 置對象池為空
        objects = null;
    }

    /**
     * 使程序等待給定的毫秒數
     */
    private void wait(int mSeconds) {
        try {
            Thread.sleep(mSeconds);
        } catch (InterruptedException e) {
        }
    }
}

為了泛化處理,這個對象池是個抽象類,接下來具體實現一個

public class DefaultObjectPool extends ObjectPool<String> {

    @Override
    public PooledObject<String> create(){
        return new PooledObject<String>(new String(""+1));
    }

}

最后測試下:

    public static void main(String[] args) {
        ObjectPool<String> objPool = new DefaultObjectPool();
        objPool.createPool();
        String obj = objPool.getObject();
        objPool.returnObject(obj);
        objPool.closeObjectPool();
    }

4、開源的對象池

上面的例子基本夠用,但是commons-pool提供了一套很好用的對象池組件,使用也很簡單。
org.apache.commons.pool.ObjectPool定義了一個簡單的池化接口,有三個對應實現,與我們的 Vector 這個集合不同的是,commons-pool提供了多樣的集合,包括先進先出(FIFO),后進先出(LIFO)

StackObjectPool :實現了后進先出(LIFO)行為。
SoftReferenceObjectPool: 實現了后進先出(LIFO)行為。另外,對象池還在SoftReference 中保存了每個對象引用,允許垃圾收集器針對內存需要回收對象。

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

PoolableObjectFactory 定義了池化對象的生命周期方法,我們可以使用它分離被池化的不同對象和管理對象的創建,持久,銷毀。
BasePoolableObjectFactory這個實現PoolableObjectFactory接口的一個抽象類,我們可用擴展它實現自己的池化工廠。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容