commons.pool2 物件池的使用
阿新 • • 發佈:2019-01-06
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);
}
}
}
}
參考: