commons.pool2 對象池的使用

commons.pool2 對象池的使用java

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.3</version>
</dependency>


池對象工廠 PooledObjectFactory和池對象 DefaultPooledObject

先了解個概念:apache

池對象工廠(PooledObjectFactory接口):用來建立池對象, 將不用的池對象進行鈍化(passivateObject), 對要使用的池對象進行激活(activeObject), 對池對象進行驗證(validateObject), 對有問題的池對象進行銷燬(destroyObject)等工做ide

PooledObjectFactory是一個池化對象工廠接口,定義了生成對象、激活對象、鈍化對象、銷燬對象的方法,以下spa

public interface PooledObjectFactory<T> {
    PooledObject<T> makeObject() throws Exception;

    void destroyObject(PooledObject<T> var1) throws Exception;

    boolean validateObject(PooledObject<T> var1);

    void activateObject(PooledObject<T> var1) throws Exception;

    void passivateObject(PooledObject<T> var1) throws Exception;
}

若是須要使用Commons-Pool,那麼你就須要提供一個PooledObjectFactory接口的具體實現。一個比較簡單的辦法就是,繼承BasePooledObjectFactory這個抽象類。而繼承這個抽象類,只須要實現兩個方法:create()和wrap(T obj)。code

實現create()方法很簡單,而實現wrap(T obj)也有捷徑,可使用類DefaultPooledObject,代碼能夠參考以下:xml

import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;

/**
 * Created by liyanxin on 2015/3/25.
 */
public class PooledStringBufferFactory extends BasePooledObjectFactory<StringBuffer> {

    @Override
    public StringBuffer create() throws Exception {
        return new StringBuffer(16);
    }

    @Override
    public PooledObject<StringBuffer> wrap(StringBuffer stringBuffer) {
        return new DefaultPooledObject<StringBuffer>(stringBuffer);
    }
}

固然還有其餘的池對象工廠,如KeyedPooledObjectFactory,和PooledObjectFactory接口相似,只是在相關的方法中多了Key參數,以下,對象

public interface KeyedPooledObjectFactory<K,V> {
   
    PooledObject<V> makeObject(K key) throws Exception;
  
    void destroyObject(K key, PooledObject<V> p) throws Exception;

    boolean validateObject(K key, PooledObject<V> p);
   
    void activateObject(K key, PooledObject<V> p) throws Exception;

    void passivateObject(K key, PooledObject<V> p) throws Exception;
}


建立對象池 GenericObjectPool

在org.apache.commons.pool2.impl中預設了三個能夠直接使用的對象池:GenericObjectPool、GenericKeyedObjectPool和SoftReferenceObjectPool。繼承

一般使用GenericObjectPool來建立對象池,若是是對象池是Keyed的,那麼可使用GenericKeyedObjectPool來建立對象池。這兩個類都提供了豐富的配置選項。這兩個對象池的特色是能夠設置對象池中的對象特徵,包括LIFO(後進先出)方式、最大空閒數、最小空閒數、是否有效性檢查等等。二者的區別如前面所述,後者支持Keyed。接口

而SoftReferenceObjectPool對象池,它利用一個java.util.ArrayList對象來保存對象池裏的對象。不過它並不在對象池裏直接保存對象自己,而是保存它們的「軟引用」隊列

(Soft Reference)。這種對象池的特點是:能夠保存任意多個對象,不會有容量已滿的狀況發生;在對象池已空的時候,調用它的borrowObject方法,會自動返回新建立的實例;能夠在初始化同時,在池內預先建立必定量的對象;當內存不足的時候,池中的對象能夠被Java虛擬機回收。

舉個例子:

new GenericObjectPool<StringBuffer>(new PooledStringBufferFactory());

咱們也可使用GenericObjectPoolConfig來對上面建立的對象池進行一些參數配置,建立的Config參數,可使用setConfig方法傳給對象池,也能夠在對象池的構造方法中做爲參數傳入。

舉個例子:

GenericObjectPoolConfig conf = new GenericObjectPoolConfig();
conf.setMaxTotal(20);
conf.setMaxIdle(10);
...
GenericObjectPool<StringBuffer> pool = new GenericObjectPool<StringBuffer>(new PooledStringBufferFactory(), conf);


使用對象池

對象池使用起來很方便,簡單一點就是使用borrowObject和returnObject兩個方法,直接給參考代碼吧:

borrowObject部分代碼,具體請看源碼:借出池對象,經過新建create()或從idleObjects雙端隊列中返回池對象。idleObjects是一個雙端隊列,保存返回對象池的對象,下次用的時候按照LIFO的原則(或其餘原則)借出對象。

public T borrowObject(long borrowMaxWaitMillis) throws Exception {
    PooledObject<T> p = null;

    while (p == null) {
        create = false;
        if (blockWhenExhausted) {
            p = idleObjects.pollFirst();
            if (p == null) {
                p = create();
                if (p != null) {
                    create = true;
                }
            }
            if (p == null) {
                if (borrowMaxWaitMillis < 0) {
                    p = idleObjects.takeFirst();
                } else {
                    p = idleObjects.pollFirst(borrowMaxWaitMillis,
                            TimeUnit.MILLISECONDS);
                }
            }
            if (p == null) {
                throw new NoSuchElementException(
                        "Timeout waiting for idle object");
            }
            if (!p.allocate()) {
                p = null;
            }
        } else {
            p = idleObjects.pollFirst();
            if (p == null) {
                p = create();
                if (p != null) {
                    create = true;
                }
            }
        }
    }
    return p.getObject();
}

returnObject方法,部分代碼,具體請看源碼:返回池對象,放入idleObjects雙端隊列保存。

關鍵代碼:

public void returnObject(T obj) {
    PooledObject<T> p = allObjects.get(obj);

    int maxIdleSave = getMaxIdle();
    if (isClosed() || maxIdleSave > -1 && maxIdleSave <= idleObjects.size()) {
        try {
            destroy(p);
        } catch (Exception e) {
            swallowException(e);
        }
    } else {
        if (getLifo()) {
            idleObjects.addFirst(p);
        } else {
            idleObjects.addLast(p);
        }
    }
    updateStatsReturn(activeTime);
}

這只是大致上的邏輯,還有更多的細節邏輯控制。好比何時銷燬,何時建立等等。

==============END==============

相關文章
相關標籤/搜索