Object pool就是一個管理對象的池子。新版本利用jdk 1.5以后的特性,結合泛型,而不是利用Object來實現了。
主要就靠3個接口來管理:
ObjectPool, 定義了池接口,就是說,以后的對象池,至少模子是這個樣子的~~主要兩個實現抽象類:BaseObjectPool和KeyedObjectPool。有一些基本方法比如從對象池取對象,調用borrowObject()方法,將對象放回使用returnObject()方法。清空選擇clear,而不需要對象池選擇關閉時使用close等。在具體的Pool實現中,會依賴PoolableObjectFactory接口。
PoolableObjectFactory,怎么理解這個接口呢?其實在ObjectPool中我們看到只是聲明了一些調用和放回對象的方法,可以理解為真正我們在操作一個pool,這就是一個數據結構。然而pool中的對象創建、管理、銷毀等事務pool管不了了。因此框架又定義了這樣一個factory去管理這些對象。該接口有makeObject方法,我們自己的factory實現里可以利用這個方法去創建個性化的對象。有創建就有銷毀,destroyObject(T obj)方法就用來銷毀對象。同時還有activateObject(T obj)方法用來激活對象,也就是說令對象可用。有passivateObject(T obj)方法用來將對象作為idle狀態。同時還有validateObject(T obj)方法來檢驗對象是否可以由pool安全返回。
ObjectPoolFactory,作為最后一個接口,我感覺這個factory應該算是用處不特別大吧。顧名思義,用來管理pool的一個factory。我們的應用如果需要的話,可能不止一個pool。由一個factory去管理,明顯合理的,而且factory模式也是pool框架的特色。該接口只有一個方法,那就是createObjectPool()。
框架的類圖主要關系就是這樣
圖片來源是http://commons.apache.org/pool/guide/classdiagrams.html。只需要看清楚幾個接口的關系就可以了。
那么最好還是舉例看看一個pool如何使用吧。例子是commons-pool1.4版本,jdk1.6
<代碼修改自參考資料http://www.ibm.com/developerworks/cn/java/l-common-pool/>
首先定義一個對象(一般使用線程池的原則是對象比較大,所以我們就叫它大對象):
1: /**
2: *
3: */
4: package common.pool;
5:
6: /**
7: * @author Administrator
8: *
9: */
10: public class BigObject {
11:
12: private boolean active;
13:
14: public boolean isActive() {
15: return active;
16: }
17:
18: public void setActive(boolean active) {
19: this.active = active;
20: }
21:
22: public BigObject() {
23: active = true;
24: System.out.println("i am a big object!!!");
25: }
26:
27: public String toString() {
28: return "big object "+ this.hashCode();
29: }
30: }
接著去實現PoolableObjectFactory:
1: /**
2: *
3: */
4: package common.pool;
5:
6: import org.apache.commons.pool.*;
7: /**
8: * @author Administrator
9: *
10: */
11: public class TestFactory implements PoolableObjectFactory{
12:
13: @Override
14: public void activateObject(Object arg0) throws Exception {
15: // TODO Auto-generated method stub
16: ((BigObject)arg0).setActive(true);
17: }
18:
19: @Override
20: public void destroyObject(Object arg0) throws Exception {
21: // TODO Auto-generated method stub
22: arg0 = null;
23: }
24:
25: @Override
26: public Object makeObject() throws Exception {
27: // TODO Auto-generated method stub
28: BigObject bo = new BigObject();
29: return bo;
30: }
31:
32: @Override
33: public void passivateObject(Object arg0) throws Exception {
34: // TODO Auto-generated method stub
35: ((BigObject)arg0).setActive(false);
36: }
37:
38: @Override
39: public boolean validateObject(Object arg0) {
40: // TODO Auto-generated method stub
41: if(((BigObject)arg0).isActive())
42: return true;
43: else
44: return false;
45: }
46:
47: }
最后測試:
1: /**
2: *
3: */
4: package common.pool;
5:
6: import org.apache.commons.pool.ObjectPool;
7: import org.apache.commons.pool.PoolableObjectFactory;
8: import org.apache.commons.pool.impl.StackObjectPool;
9:
10:
11: /**
12: * @author Administrator
13: *
14: */
15: public class PoolTest {
16:
17: /**
18: * @param args
19: */
20: public static void main(String[] args) {
21: // TODO Auto-generated method stub
22: BigObject bo = null;
23: PoolableObjectFactory factory = new TestFactory();
24: ObjectPool pool = new StackObjectPool(factory);
25: try {
26: for(long i = 0; i < 10 ; i++) {
27: System.out.println("== " + i + " ==");
28: bo = (BigObject) pool.borrowObject();
29: System.out.println(bo);
30: System.out.println(pool.getNumActive());
31: if((i&1)==0) {
32: pool.returnObject(bo);
33: }
34: }
35: // bo = null;//明確地設為null,作為對象已歸還的標志
36: }
37: catch (Exception e) {
38: e.printStackTrace();
39: }
40: finally {
41: try{
42: if (bo != null) {//避免將一個對象歸還兩次
43: pool.returnObject(bo);
44: }
45: pool.close();
46: }
47: catch (Exception e){
48: e.printStackTrace();
49: }
50: }
51:
52: }
53:
54: }
55:
結束了,一個pool的簡單應用就搞定了。下面我們看看代碼的具體實現是什么。
先看看pool構造時候都做了些什么:
StackObjectPool里有兩個protected field,一個protected PoolableObjectFactory _factory = null;一個protected Stack _pool = null;。前者是通過構造方法注入的一個factory,我們的代碼里已經自己實現了一個TestFactory;后者是具體的Pool管理策略,像StackObjectPool的話就是內部用這樣一個Stack來管理對象。
構造時會通過
1: public StackObjectPool(PoolableObjectFactory factory, int maxIdle, int initIdleCapacity) {
2: _factory = factory;
3: _maxSleeping = (maxIdle < 0 ? DEFAULT_MAX_SLEEPING : maxIdle);
4: int initcapacity = (initIdleCapacity < 1 ? DEFAULT_INIT_SLEEPING_CAPACITY : initIdleCapacity);
5: _pool = new Stack();
6: _pool.ensureCapacity( initcapacity > _maxSleeping ? _maxSleeping : initcapacity);
7: }
來完成初始參數和變量的構造。
接著我們開始從pool中取對象了,調用borrowObject的方法,具體實現在源碼中是這樣的:
1: public synchronized Object borrowObject() throws Exception {
2: assertOpen();
3: Object obj = null;
4: boolean newlyCreated = false;
5: while (null == obj) {
6: if (!_pool.empty()) {
7: obj = _pool.pop();
8: } else {
9: if(null == _factory) {
10: throw new NoSuchElementException();
11: } else {
12: obj = _factory.makeObject();
13: newlyCreated = true;
14: if (obj == null) {
15: throw new NoSuchElementException("PoolableObjectFactory.makeObject() returned null.");
16: }
17: }
18: }
19: if (null != _factory && null != obj) {
20: try {
21: _factory.activateObject(obj);
22: if (!_factory.validateObject(obj)) {
23: throw new Exception("ValidateObject failed");
24: }
25: } catch (Throwable t) {
26: try {
27: _factory.destroyObject(obj);
28: } catch (Throwable t2) {
29: // swallowed
30: } finally {
31: obj = null;
32: }
33: if (newlyCreated) {
34: throw new NoSuchElementException(
35: "Could not create a validated object, cause: " +
36: t.getMessage());
37: }
38: }
39: }
40: }
41: _numActive++;
42: return obj;
43: }
在不考慮同步的時候,我們只看對象的創建,典型的幾個if邏輯就完成了這樣的功能,在pool空時,就用factory的makeObject方法,不空則直接從內置stack里pop一個對象出來。接著在對象構造OK后,開始激活這個對象。接著調用validate去校驗,如果不合格就跑出異常,而異常的捕獲中又會嘗試去destroy對象,再有問題的話只有swallow掉異常了。整個pool會有一個_numActive變量來控制活著(被borrow但沒被return)的對象數,每次borrow后都會加一。而循環是到obj不空時才退出的,所以obj不會為null。所以,只要你的makeObject合理的不返回null,那么這個邏輯就不會死循環。當然整個過程中似乎都會有多線程安全問題,所以整個方法都加同步。但是這顯然不是完美的解決方法,對于復雜的多線程問題,調度還需要程序員自己來控制。
接著就是returnObject了,顧名思義就是把從pool中借出來的object還回去。邏輯代碼如下:
1: public synchronized void returnObject(Object obj) throws Exception {
2: boolean success = !isClosed();
3: if(null != _factory) {
4: if(!_factory.validateObject(obj)) {
5: success = false;
6: } else {
7: try {
8: _factory.passivateObject(obj);
9: } catch(Exception e) {
10: success = false;
11: }
12: }
13: }
14:
15: boolean shouldDestroy = !success;
16:
17: _numActive--;
18: if (success) {
19: Object toBeDestroyed = null;
20: if(_pool.size() >= _maxSleeping) {
21: shouldDestroy = true;
22: toBeDestroyed = _pool.remove(0); // remove the stalest object
23: }
24: _pool.push(obj);
25: obj = toBeDestroyed; // swap returned obj with the stalest one so it can be destroyed
26: }
27: notifyAll(); // _numActive has changed
28:
29: if(shouldDestroy) { // by constructor, shouldDestroy is false when _factory is null
30: try {
31: _factory.destroyObject(obj);
32: } catch(Exception e) {
33: // ignored
34: }
35: }
36: }
首先一個success變量作為判斷位來決定對象能否放回pool。如果經過validate后發現對象不合格,那么顯然不能放回pool了。如果validate合格,那么就嘗試用factory的passivateObject方法使對象變為not active。接著進入邏輯判斷如果可以放回,那么嘗試將對象push到pool的內置stack中,嘗試時會有閾值限定,如果超過了閾值的話,那么需要以某種策略將stack中的對象remove掉一個。而策略如果仔細看代碼就會發現很合理,首先在stack中remove最老的一個,然后將這個remove值保存為臨時變量,將待放回對象push到stack,接著將臨時對象轉接到帶放回對象上。我們看到,這樣的一組行為保證了幾個對象的銷毀,而不會出現內存泄露。
最后附上apache官網上的幾張時序圖來完美解釋borrow和return的過程:
![clip_image002[6] clip_image002[6]](http://m.tkk7.com/images/blogjava_net/changedi/Windows-Live-Writer/commons-pool_9602/clip_image002%5B6%5D_thumb.jpg)
基本介紹到此,后續可能有進階研究,期待時間~~
參考資料:
http://www.ibm.com/developerworks/cn/java/l-common-pool/
http://commons.apache.org/pool