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的过程:
基本介绍到此,后续可能有进阶研究,期待时间~~
参考资料:
http://www.ibm.com/developerworks/cn/java/l-common-pool/
http://commons.apache.org/pool