一、摘要
apache common pool2 作為對象池模式的一種實(shí)現(xiàn),通過重用來分?jǐn)倧?fù)雜對象的創(chuàng)建代價(jià)。被廣泛應(yīng)用在各種數(shù)據(jù)庫連接池,線程池以及請求分發(fā)池中;其實(shí)現(xiàn)提供了一些參數(shù)來控制對象池的行為,了解這些參數(shù)對學(xué)習(xí)其他“池”技術(shù)很有必要。
二、對象池
對象池模式解決的問題:
管理那些代表的現(xiàn)實(shí)資源或者通過重用來分?jǐn)偘嘿F初始化代價(jià)的對象。
對象的創(chuàng)建和銷毀在一定程度上會消耗系統(tǒng)的資源,雖然jvm的性能在近幾年已經(jīng)得到了很大的提高,對于多數(shù)對象來說,沒有必要利用對象池技術(shù)來進(jìn)行對象的創(chuàng)建和管理。但是對于有些對象來說,其創(chuàng)建的代價(jià)還是比較昂貴的,比如線程、tcp連接、數(shù)據(jù)庫連接等對象,因此對象池技術(shù)還是有其存在的意義。
對象池模式:
對象池模式管理一個(gè)可代替對象的集合。組件從池中借出對象,用它來完成一些任務(wù)并當(dāng)任務(wù)完成時(shí)歸還該對象。被歸還的對象接著滿足請求,不管是同一個(gè)組件還是其他組件的請求。
優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn); 復(fù)用池中對象,沒有分配內(nèi)存和創(chuàng)建堆中對象的開銷, 沒有釋放內(nèi)存和銷毀堆中對象的開銷, 進(jìn)而減少垃圾收集器的負(fù)擔(dān), 避免內(nèi)存抖動;不必重復(fù)初始化對象狀態(tài)。
- 缺點(diǎn):
1. 并發(fā)環(huán)境下,對象池操作的同步成為一大開銷;
2. 很難正確設(shè)置對象池大小,太小不起作用,太大浪費(fèi)資源。
三、 common pool2 核心
Apache Common-pool2包提供了一個(gè)通用的對象池技術(shù)的實(shí)現(xiàn)。可以很方便的基于它來實(shí)現(xiàn)自己的對象池,比如DBCP和Jedis他們的內(nèi)部對象池的實(shí)現(xiàn)就是依賴于Common-pool2。
Common-pool2由三大模塊組成:ObjectPool
、PooledObject
和PooledObjectFactory
。
它們的關(guān)系如下:
- ObjectPool:提供所有對象的存取管理。
- PooledObject:池化的對象,是對真正對象的一個(gè)包裝,加上了對象的一些其他信息,包括對象的狀態(tài)(已用、空閑),對象的創(chuàng)建時(shí)間等。其實(shí)現(xiàn)要求是線程安全的。
- PooledObjectFactory:工廠類,負(fù)責(zé)池化對象的創(chuàng)建,對象的初始化,對象狀態(tài)的銷毀和對象狀態(tài)的驗(yàn)證。其實(shí)現(xiàn)要求是線程安全的。
通常,ObjectPool會持有PooledObjectFactory,將具體的對象的創(chuàng)建、初始化、銷毀等任務(wù)委托給PooledObjectFactory處理,工廠操作的對象是PooledObject,即具體的Object的包裝類。因此,獲取對象依賴ObjectPool而不是PooledObjectFactory。
池化對象于真正對象的區(qū)別
ObjectPool提供出去的對象是真正對象,而不是池化對象;池化對象是對象池的概念,為管理真正對象的相關(guān)細(xì)節(jié)提供支持。
PooledObject的實(shí)現(xiàn)會組合真正的對象。
PooledObjectFactory工廠產(chǎn)生的也是池化對象,而不是真正對象。
自定義對象池
以上三個(gè)抽象組件定義了 apache common pool2的標(biāo)準(zhǔn),自定義對象池分別實(shí)現(xiàn)這三個(gè)抽象組件:
- ObjectPool的實(shí)現(xiàn),主要提供borrow/return池化對象,調(diào)用者可直接使用,或者通過組合的方式使用對象池。
- PooledObjectFactory的實(shí)現(xiàn),用以產(chǎn)生池化對象。
- PooledObject的實(shí)現(xiàn),包裝真正對象。
apache common pool2也提供了自己的對象池實(shí)現(xiàn)來簡化開發(fā),自定義對象池完全可以依賴這個(gè)實(shí)現(xiàn)獲得強(qiáng)大的對象池功能。
四、common pool2 自帶實(shí)現(xiàn)
apache common pool2提供了一些實(shí)現(xiàn)。這里介紹一種被廣泛使用的實(shí)現(xiàn):
- ObjectPool的實(shí)現(xiàn):GenericObjectPool,提供了一個(gè)功能強(qiáng)大的對象池。
- PooledObject的實(shí)現(xiàn):DefaultPooledObject
- PooledObjectFactory的實(shí)現(xiàn):不可能提供默認(rèn)實(shí)現(xiàn),因?yàn)樯婕暗骄唧w對象的創(chuàng)建,需要使用者本身去實(shí)現(xiàn)。但是為了簡化開發(fā),提供了一個(gè)抽象的
BasePooledObjectFactory
,使用者可以選擇實(shí)現(xiàn)這個(gè)抽象類,而不是PooledObjectFactory來提供自己的池化對象工廠。
主要是對象池GenericObjectPool
的實(shí)現(xiàn),主要介紹其borrow和return池化對象的方法。
GenericObjectPool
- Map<IdentityWrapper<T>, PooledObject<T>> allObjects
- LinkedBlockingDeque<PooledObject<T>> idleObjects
主要使用以上兩個(gè)數(shù)據(jù)結(jié)構(gòu)保持池化對象。
borrow的流程
- 從idle隊(duì)列取出第一個(gè)池化對象
- 若池化對象為null,嘗試使用工廠創(chuàng)建一個(gè)池化對象
- 創(chuàng)建若createCount小于maxTotal,則使用工廠新建池化對象,否則返回null
- blockWhenExhausted只是idle為空時(shí)是否等待,maxWaitMillis只是等待多久
- 池化對象!=null;factory#activateObject
- testOnBorrow || (create && testOnCreate) factory#validateObject
return的流程
- 根據(jù)obj從allObjects取出polledObject p
- 判空;將p狀態(tài)置為RETURN
- 若getTestOnReturn參數(shù)為true,進(jìn)行factory#validateObject
- 對p進(jìn)行factory#passivateObject,與初始化相反
- 更新p狀態(tài)為IDLE
- 歸還Pool:Pool的idle實(shí)例達(dá)到上限或者Pool已經(jīng)關(guān)閉,銷毀之,否則將p加入到LinkedBlockingDeque中。
自定義對象池可以依賴GenericObjectPool以及DefaultPooledObject,只實(shí)現(xiàn)PooledObjectFactory即可。
對象池屬性
org.apache.commons.pool2.impl.GenericObjectPool
對象池屬性,控制對象池產(chǎn)生對象的行為;
全部屬性由org.apache.commons.pool2.impl.BaseGenericObjectPool
描述:
屬性 | 值 | 說明 |
---|---|---|
borrow: | ||
maxTotal | long;默認(rèn)-1 | idle隊(duì)列為空,idle.len < maxTotal可創(chuàng)建,-1時(shí)maxTotal為整數(shù)最大值 |
blockWhenExhausted | true[默認(rèn)]/false | idle空,maxTotal達(dá)到,是否等待隊(duì)列 |
maxWaitMillis | long;默認(rèn)-1 | idle空,maxTotal達(dá)到blockWhenExhausted=true,等待隊(duì)列時(shí)長;-1一直等 |
testOnBorrow | true/false[默認(rèn)] | borrow時(shí),控制objFactory#validateObject |
testOnCreate | true/false[默認(rèn)] | borrow時(shí),通過create獲得,控制objFactory#validateObject |
return: | ||
testOnReturn | true/false[默認(rèn)] | objPool#returnObj,控制 objFactory#validateObject |
lifo | true[默認(rèn)]/false | true-LIFO idle隊(duì)列后進(jìn)先出; false-FIFO idle隊(duì)列先進(jìn)先出 |
五、自定義對象池
使用默認(rèn)對象池GenericObjectPool,只需定義池化對象工廠即可。
官方提供了demo 官方demo
以下為簡化,更容易看清本質(zhì):
池化對象工廠:產(chǎn)生StringBuffer對象
public class StringBufferFactory extends BasePooledObjectFactory<StringBuffer> {
@Override
public StringBuffer create() throws Exception {
return new StringBuffer();
}
// 直接使用DefaultPooledObject包裝真正對象StringBuffer,提供池化對象
@Override
public PooledObject<StringBuffer> wrap(StringBuffer obj) {
return new DefaultPooledObject<>(obj);
}
@Override
public void passivateObject(PooledObject<StringBuffer> p) throws Exception {
p.getObject().setLength(0);
}
}
使用
public static void main(String[] args) throws Exception {
// 直接使用 apache common pool2提供的對象池,將創(chuàng)建池化對象細(xì)節(jié)委托給自定義的工廠即可。
GenericObjectPool<StringBuffer> pool = new GenericObjectPool<>(new StringBufferFactory());
// 從對象池借真正對象
StringBuffer stringBuffer = pool.borrowObject();
// do something with string buffer.
// 歸還
pool.returnObject(stringBuffer);
}
refer to
創(chuàng)建者模式-對象池模式(The Object Pool Pattern)
Apache Common Pool2 對象池應(yīng)用淺析