Object Pool,即对象池,对象被预先创建并初始化后放入对象池中,对象提供者就能利用已有的对象来处理请求,减少对象频繁创建所占用的内存空间和初始化时间,例如数据库连接对象基本上都是创建后就被放入连接池中,后续的查询请求使用的是连接池中的对象,从而加快了查询速度。类似被放入对象池中的对象还包括Socket对象、线程对象和绘图对象(GDI对象)等。
在Object Pool设计模式中,主要有两个参与者:对象池的管理者和对象池的用户,用户从管理者那里获取对象,对象池对于用户来讲是透明的,但是用户必须遵守这些对象的使用规则,使用完对象后必须归还或者关闭对象,例如数据库连接对象使用完后必须关闭,否则该对象就会被一直占用着。
对象管理者需要维护对象池,包括初始化对象池、扩充对象池的大小、重置归还对象的状态等。
对象池在被初始化时,可能只有几个对象,甚至没有对象,按需创建对象能节省资源和时间,对于响应时间要求较高的情况,可以预先创建若干个对象。
当对象池中没有对象可供使用时,管理者一般需要使用某种策略来扩充对象池,比如将对象池的大小翻倍。另外,在多线程的情况下,可以让请求资源的线程等待,直到其他线程归还了占用的对象。
一般来说,对象池中的对象在逻辑状态上是相同的,如果都是无状态对象(即没有成员变量的对象),那么这些对象的管理会方便的多,否则,对象被使用后的状态重置工作就要由管理者来承担。
下面是一个非常简单的例子:
public class MyObject {
public void doSomething(){
// 执行某种任务
}
}
public interface MyObjectPool{
MyObject borrowObject();
void returnObject(MyObject obj);
}
public class MyObjectPoolImpl implements MyObjectPool{
private List objects;
MyObject borrowObject(){
return objects.get(0);
}
void returnObject(MyObject obj){
objects.add(obj);
}
}
下面是一段使用线程池的代码:
MyObjectPool pool = new MyObjectPoolImpl();
MyObject obj = pool.borrowObject();
obj.doSomething();
pool.returnObject(obj);
对于具体的实现,我们可以将对象池的信息暴露给用户,比如当前可用的对象数量,另外,也可以把对象池的部分控制权暴露给用户,比如用户可以主动要求扩充对象池的大小、向池中添加对象等。一般来说,一个线程池只能容纳某种特定类型的对象,不过,我们可以通过将对象池中的对象增加一个类型的标记来支持任意类型的对象,MyObjectPool的声明就变成了下面的样子:
public interface MyKeyObjectPool{
MyObject borrowObject(String key);
void returnObject(MyObject obj,String key);
}