原文地址: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);@Overridepublic 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