Apache Commons 系列簡介 之 Pool

Love Lenka發表於2016-12-29

一、概述

Apache Commons Pool庫提供了一整套用於實現物件池化的API,以及若干種各具特色的物件池實現。2.0版本,並非是對1.x的簡單升級,而是一個完全重寫的物件池的實現,顯著的提升了效能和可伸縮性,並且包含可靠的例項跟蹤和池監控。第二版要求JDK1.6+。

二、下載

官方下載頁:

http://commons.apache.org/proper/commons-pool/download_pool.cgi

原始碼:

svn checkout http://svn.apache.org/repos/asf/commons/proper/pool/trunk commons-pool2

Maven工程依賴

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

三、使用說明

3.1 建立池化物件

建立池化物件很簡單,只要實現commons-poolPooledObjectFactory工廠介面就行了。

PooledObjectFactory是一個池化物件工廠介面,定義了生成物件、啟用物件、鈍化物件、銷燬物件的方法,如下:

public interface PooledObjectFactory<T> {
    PooledObject<T> makeObject();
    void activateObject(PooledObject<T> obj);
    void passivateObject(PooledObject<T> obj);
    boolean validateObject(PooledObject<T> obj);
    void destroyObject(PooledObject<T> obj);
}

它建立並管理PooledObjectPooledObject包含了池化的物件例項,以及這些例項的池化屬性,比如建立時間、最後使用時間等等。

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

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

@Override
public PooledObject<Foo> wrap(Foo foo) {
    return new DefaultPooledObject<Foo>(foo);
}

比如,一個完整的例子:

package test.test;

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

public class StringBufferFactory extends BasePooledObjectFactory<StringBuffer> {

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

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

}

有時候,單用對池內所有物件一視同仁的物件池,並不能解決問題。例如,有時需要透過key來獲取不同的物件,這樣,就有可能取出不合用的物件的麻煩。當然,可以透過為每一組引數相同的同類物件建立一個單獨的物件池來解決這個問題。但是,如果使用普通的ObjectPool來實施這個計策的話,因為普通的PooledObjectFactory只能生產出大批設定完全一致的物件,就需要為每一組引數相同的物件編寫一個單獨的PooledObjectFactory,工作量相當可觀。這種時候就可以使用BaseKeyedPooledObjectFactory來替代BasePooledObjectFactory.這個類,實現的是KeyedPooledObjectFactory介面,和PooledObjectFactory介面類似,只是在相關的方法中多了Key引數,定義如下:

public interface KeyedPoolableObjectFactory<K,V> {
    PooledObject<V> makeObject(K key);
    void activateObject(K key, PooledObject<V> obj);
    void passivateObject(K key, PooledObject<V> obj);
    boolean validateObject(K key, PooledObject<V> obj);
    void destroyObject(K key, PooledObject<V> obj);
}

3.2 建立物件池

org.apache.commons.pool2.impl中預設了三個可以直接使用的物件池:GenericObjectPoolGenericKeyedObjectPoolSoftReferenceObjectPool

通常使用GenericObjectPool來建立物件池,如果是物件池是Keyed的,那麼可以使用GenericKeyedObjectPool來建立物件池。這兩個類都提供了豐富的配置選項。這兩個物件池的特點是可以設定物件池中的物件特徵,包括LIFO方式、最大空閒數、最小空閒數、是否有效性檢查等等。兩者的區別如前面所述,後者支援Keyed

SoftReferenceObjectPool物件池,它利用一個java.util.ArrayList物件來儲存物件池裡的物件。不過它並不在物件池裡直接儲存物件本身,而是儲存它們的“軟引用”(Soft Reference)。這種物件池的特色是:可以儲存任意多個物件,不會有容量已滿的情況發生;在物件池已空的時候,呼叫它的borrowObject方法,會自動返回新建立的例項;可以在初始化同時,在池內預先建立一定量的物件;當記憶體不足的時候,池中的物件可以被Java虛擬機器回收。

舉個例子:

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

我們也可以使用GenericObjectPoolConfig來對上面建立的物件池進行一些引數配置,建立的Config引數,可以使用setConfig方法傳給物件池,也可以在物件池的構造方法中作為引數傳入。

舉個例子:

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

3.3 使用物件池

物件池使用起來很方便,簡單一點就是使用borrowObjectreturnObject兩個方法,直接給參考程式碼吧:

StringBuffer buf = null;
try { 
    buf = pool.borrowObject();
    ...         
} catch(IOException e) { 
    throw e; 
} catch(Exception e) {
    throw new RuntimeException("Unable to borrow buffer from pool" + 
          e.toString());
} finally { 
    try {
        if(null != buf) {
            pool.returnObject(buf);
        }
    } catch(Exception e) {
        // ignored
    }
} 






 

相關文章