原文地址:https://jaune162.blog/design-pattern/object-pool-pattern/
原文中可下载高清SVG矢量类图
引言
对象池模式(Object Pool Pattern)是一种创建一组可重用对象的设计模式。它通过维护一个预分配的对象集合,避免了频繁地创建和销毁对象所带来的性能开销。在需要使用对象时,可以直接从池中获取,而不需要每次都创建新的对象;当对象不再使用时,可以将其归还到池中,而不是直接销毁。
对象池模式的主要优点是减少了对象的创建和销毁的开销,提高了程序的性能。此外,它还有助于控制资源的使用,避免资源的浪费。然而,对象池模式也有一些缺点,如增加了代码的复杂性,以及可能导致内存占用过高。
对象池模式并不是GoF中的23种设计模式
定义及实现
定义
When objects are expensive to create and they are needed only for short periods of time it is advantageous to utilize the Object Pool pattern. The Object Pool provides a cache for instantiated objects tracking which ones are in use and which are available.
当对象的创建成本很高并且只在很短的周期内使用,那么对象池模式就很有优势。对象池提供一个对象示例的缓存来跟踪那个对象正在使用,哪个对象是可用的。
结构
代码实现
@Slf4j
public abstract class ObjectPool<T> {
private final Deque<T> available = new ArrayDeque<>();
private final Deque<T> using = new ArrayDeque<>();
/**
* 创建一个对象
*/
protected abstract T create();
/**
* 从池中获取一个对象
*/
public synchronized T checkOut() {
if (available.isEmpty()) {
T obj = this.create();
using.addLast(obj);
return obj;
}
T obj = available.poll();
using.addLast(obj);
return obj;
}
/**
* 将对象放回池中
*/
public synchronized void checkIn(T t) {
using.remove(t);
available.addLast(t);
}
public void printPoolInfo() {
log.info("available: {}, using: {}", available.size(), using.size());
}
}
@Slf4j
public class Oliphaunt {
// 这里类中定义一个序号,用来区分不同的实例
private final Integer sno;
public Oliphaunt(Integer sno) {
this.sno = sno;
}
public void doSomething() {
log.info("sno: {}, do something", this.sno);
}
}
public class OliphauntObjectPool extends ObjectPool<Oliphaunt> {
private final AtomicInteger count = new AtomicInteger(1);
@Override
public Oliphaunt create() {
return new Oliphaunt(count.getAndIncrement());
}
}
测试对象池的使用
public class Main {
public static void main(String[] args) {
ObjectPool<Oliphaunt> oliphauntObjectPool = new OliphauntObjectPool();
Oliphaunt oliphaunt = oliphauntObjectPool.checkOut();
Oliphaunt oliphaunt2 = oliphauntObjectPool.checkOut();
oliphaunt.doSomething();
oliphaunt2.doSomething();
oliphauntObjectPool.checkIn(oliphaunt);
oliphauntObjectPool.checkIn(oliphaunt2);
Oliphaunt oliphaunt3 = oliphauntObjectPool.checkOut();
oliphaunt3.doSomething();
oliphauntObjectPool.printPoolInfo();
}
}
输出结果
org.depsea.design.pattern.creation.objectpool.Oliphaunt -- sno: 1, do something
org.depsea.design.pattern.creation.objectpool.Oliphaunt -- sno: 2, do something
org.depsea.design.pattern.creation.objectpool.Oliphaunt -- sno: 1, do something
org.depsea.design.pattern.creation.objectpool.ObjectPool -- available: 1, using: 1
存在的问题
以上实现有一个使用起来不太方便的地方,每次使用完后都需要通过对象池的 checkIn
方法归还对象。但是我们在使用连接池获取连接,使用完毕后好像并没有这个操作,而是直接调用连接的 close
方法即可。这是如何实现的呢?这里提供一个思路。
使Oliphaut
实现Closeable
并提供一个关闭函数close
,并在 Oliphaunt
中提供一个钩子函数,用于在Oliphaunt
创建时,创建者可以注入一个钩子,这个钩子函数的目的就是将对象返还到连接池中。然后Oliphaut
在关闭函数中调用这个钩子,就可以达到回收对象的目的。
我们需要对 Oliphaut
和 OliphauntObjectPool
稍加改造。
@Slf4j
public class Oliphaunt implements Closeable {
// 这里类中定义一个序号,用来区分不同的实例
private final Integer sno;
@Sette