1. 程式人生 > >commons.pool2 物件池的使用

commons.pool2 物件池的使用

maven依賴

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

核心元素

  • PooledObjectFactory: 定義池化物件如何被建立、銷燬及初始化等行為;
  • GenericObjectPool:物件池,管理池中的物件;

物件的生命週期

在這裡插入圖片描述

物件池配置說明GenericObjectPoolConfig

  • maxActive: 連結池中最大連線數,預設為8;
  • maxIdle: 連結池中最大空閒的連線數,預設為8;
  • minIdle: 連線池中最少空閒的連線數,預設為0;
  • maxWait: 當連線池資源耗盡時,呼叫者最大阻塞的時間,超時將跑出異常。單位,毫秒數;預設為-1.表示永不超時;
  • minEvictableIdleTimeMillis: 連線空閒的最小時間,達到此值後空閒連線將可能會被移除,負值(-1)表示不移除;
  • softMinEvictableIdleTimeMillis: 連線空閒的最小時間,達到此值後空閒連結將會被移除,且保留“minIdle”個空閒連線數,預設為-1;
  • numTestsPerEvictionRun: 對於“空閒連結”檢測執行緒而言,每次檢測的連結資源的個數,預設為3;
  • testOnBorrow: 向呼叫者輸出“連結”資源時,是否檢測是有有效,如果無效則從連線池中移除,並嘗試獲取繼續獲取。預設為false。建議保持預設值;
  • testOnReturn: 向連線池“歸還”連結時,是否檢測“連結”物件的有效性。預設為false,建議保持預設值;
  • testWhileIdle: 向呼叫者輸出“連結”物件時,是否檢測它的空閒超時;預設為false。如果“連結”空閒超時,將會被移除。建議保持預設值;
  • timeBetweenEvictionRunsMillis: “空閒連結”檢測執行緒,檢測的週期,毫秒數。如果為負值,表示不執行“檢測執行緒”,預設為-1;
  • whenExhaustedAction: 當“連線池”中active數量達到閥值時,即“連結”資源耗盡時,連線池需要採取的手段, 預設為1:
    -> 0 : 丟擲異常,
    -> 1 : 阻塞,直到有可用連結資源
    -> 2 : 強制建立新的連結資源

PoolableObjectFactory介面說明

  • makeObject() : 建立一個新物件。當物件池中的物件個數不足時,將會使用此方法來"輸出"一個新的"物件",並交付給物件池管理;
  • destroyObject(Object obj) : 銷燬物件。如果物件池中檢測到某個"物件"idle的時間超時,或者操作者向物件池"歸還物件"時檢測到"物件"已經無效,那麼此時將會導致"物件銷燬";
  • activateObject(Object obj) : “啟用"物件。當從Pool中獲取一個物件交付給呼叫者使用前,會進行額外的"啟用"操作,比如可以在activateObject方法中"重置"引數列表讓呼叫者使用時感覺像一個"新建立"的物件一樣;如果object是一個執行緒,可以在"啟用"操作中重置"執行緒中斷標記”,或者讓執行緒從阻塞中喚醒等;如果 object是一個socket,那麼可以在"啟用操作"中重新整理通道,或者對socket進行連結重建(假如socket意外關閉)等;
  • passivateObject(Object obj) : “鈍化"物件。當呼叫者"歸還物件"時,Pool將會"鈍化物件”;鈍化的言外之意,就是此"物件"暫且需要"休息"一下.如果object是一個 socket,那麼可以passivateObject中清除buffer,將socket阻塞;需要注意的時,activateObject和passivateObject兩個方法需要對應,避免死鎖或者"物件"狀態的混亂;

BasePooledObjectFactory類提供了基本實現;

使用樣例

@Component
public class HDFSClientPool implements InitializingBean{

    private static final Logger LOGGER = LoggerFactory.getLogger(HDFSClientPool.class);

    @Value("${upload.hadoop.user.name}")
    private String hadoopUserName;

    @Value("${upload.hadoop.password}")
    private String hadoopPwd;

    private GenericObjectPool<HDFSClient> pool;

    @Override
    public void afterPropertiesSet() throws Exception {
        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
        poolConfig.setMaxIdle(10);
        poolConfig.setMaxTotal(10);
        poolConfig.setMinIdle(1);
        poolConfig.setMaxWaitMillis(30000);
        poolConfig.setMinEvictableIdleTimeMillis(300000);
        pool = new GenericObjectPool(new HDFSClientFactory(hadoopUserName, hadoopPwd), poolConfig);
        LOGGER.error(">>>>>>> GenericObjectPool: " + pool);
    }

    public HDFSClient getHDFSClient() throws Exception {
        return pool.borrowObject();
    }

    public void returnHDFSClient(HDFSClient client){
         pool.returnObject(client);
    }

    public void printActiveNum(){
        LOGGER.info("Active Num " + pool.getNumActive() + " " + pool.getNumIdle());
    }

}
public class HDFSClientFactory extends BasePooledObjectFactory<HDFSClient> {

    private static final Logger LOGGER = LoggerFactory.getLogger(HDFSClientFactory.class);

    private String hadoopUserName;

    private String hadoopPwd;

    public HDFSClientFactory(){}

    public HDFSClientFactory(String hadoopUserName, String hadoopPwd){
        this.hadoopUserName = hadoopUserName;
        this.hadoopPwd = hadoopPwd;
    }

    @Override
    public HDFSClient create() throws Exception {
        LOGGER.error("current thread create: " + Thread.currentThread().getName());
        return new HDFSClient(null, hadoopUserName, hadoopPwd);
    }

    @Override
    public PooledObject<HDFSClient> wrap(HDFSClient hdfsClient) {
        return new DefaultPooledObject<>(hdfsClient);
    }

    @Override
    public void destroyObject(PooledObject<HDFSClient> p) throws Exception {
        LOGGER.error("current thread destroy: " + Thread.currentThread().getName());
        if(p != null && p.getObject() != null){
            try{
                p.getObject().close();
                LOGGER.info("PooledObject destroy");
            }catch (Exception e){
                LOGGER.error("PooledObject destroy exception", e);
            }
        }
    }
}

參考:

  1. 引數說明:http://www.open-open.com/lib/view/open1415453575730.html
  2. https://blog.csdn.net/xlxxcc/article/details/52402931