物件池模式(Object Pool Pattern)
本文節選自《設計模式就該這樣學》
1 物件池模式的定義
物件池模式(Object Pool Pattern),是建立型設計模式的一種,將物件預先建立並初始化後放入物件池中,物件提供者就能利用已有的物件來處理請求,減少頻繁建立物件所佔用的記憶體空間和初始化時間。 一個物件池包含一組已經初始化並且可以使用的物件,可以在有需求時建立和銷燬物件。物件池的使用者可以從池子中取得物件,對其進行操作處理,並在不需要時歸還給池子而非直接銷燬。物件池是一個特殊的工廠物件,物件池模式就是單例模式加享元模式。
2 物件池模式的應用場景
物件池模式主要適用於以下應用場景。
(1)資源受限的場景。比如,不需要可伸縮性的環境(CPU\記憶體等物理資源有限),CPU效能不夠強勁,記憶體比較緊張,垃圾收集,記憶體抖動會造成比較大的影響,需要提高記憶體管理效率, 響應性比吞吐量更為重要。
(2)在記憶體中數量受限的物件。
(3)建立成本高的物件,可以考慮池化。
補充:常見的使用物件池的場景有在使用Socket時的各種連線池、執行緒池、資料庫連線池等。
3 物件池模式的UML類圖
物件池模式的UML類圖如下圖所示。
由上圖可以看到,物件池模式主要包含3個角色。
(1)物件池(ObjectPool):持有物件並提供取/還等方法。
(2)抽象池化物件(PooledObject):對池中物件的抽象。
(3)具體池化物件(ConcretePoolObject):對池中物件的封裝,封裝物件的狀態和一些其他資訊。
4 物件池模式的通用寫法
以下是物件池模式的通用寫法。
```java
public class Client {
public static void main(String[] args) {
ObjectPool pool = new ObjectPool(10,50);
IPooledObject object = pool.borrowObject();
object.operation();
pool.returnObject(object);
System.out.println();
}
//抽象物件
interface IPooledObject {
void operation();
}
//具體物件
static class ConcretePoolObject implements IPooledObject {
public void operation() {
System.out.println("doing");
}
}
//物件池
static class ObjectPool {
private int step = 10; //當物件不夠用的時候,每次擴容的數量
private int minCount;
private int maxCount;
private Vector<IPooledObject> returneds; //儲存未借出的物件
private Vector<IPooledObject> borroweds; //儲存已被借出的物件
//初始化物件池
public ObjectPool(int minCount,int maxCount){
borroweds = new Vector<IPooledObject>();
returneds = new Vector<IPooledObject>();
this.minCount = minCount;
this.maxCount = maxCount;
refresh(this.minCount);
}
//因為內部狀態具備不變性,所以作為快取的鍵
public IPooledObject borrowObject() {
IPooledObject next = null;
if(returneds.size() > 0){
Iterator<IPooledObject> i = returneds.iterator();
while (i.hasNext()){
next = i.next();
returneds.remove(next);
borroweds.add(next);
return next;
}
}else{
//計算出剩餘可建立的物件數
int count = (maxCount - minCount);
//剩餘可建立的數量大於單次固定建立的物件數
//則再初始化一批固定數量的物件
refresh(count > step ? step : count);
}
return next;
}
//不需要使用的物件歸還重複利用
public void returnObject(IPooledObject pooledObject){
returneds.add(pooledObject);
if(borroweds.contains(pooledObject)){
borroweds.remove(pooledObject);
}
}
private void refresh(int count){
for (int i = 0; i < count; i++) {
returneds.add(new ConcretePoolObject());
}
}
}
}
```
物件池模式和享元模式的最大區別在於,物件池模式中會多一個回收物件重複利用的方法。所以,物件池模式應該是享元模式更加具體的一個應用場景。相當於先將物件從物件池中借出,用完之後再還回去,以此保證有限資源的重複利用。
5 物件池模式的優缺點
5.1 優點
複用池中物件,消除建立物件、回收物件所產生的記憶體開銷、CPU開銷,以及跨網路產生的網路開銷。
5.2 缺點
(1)增加了分配/釋放物件的開銷。
(2)在併發環境中,多個執行緒可能(同時)需要獲取池中物件,進而需要在堆資料結構上進行同步或者因為鎖競爭而產生阻塞,這種開銷要比建立銷燬物件的開銷高數百倍。
(3)由於池中物件的數量有限,勢必成為一個可伸縮性瓶頸。
(4)很難合理設定物件池的大小,如果太小,則起不到作用;如果過大,則佔用記憶體資源高。 關注『 Tom彈架構 』回覆“設計模式”可獲取完整原始碼。
【推薦】Tom彈架構:30個設計模式真實案例(附原始碼),挑戰年薪60W不是夢
本文為“Tom彈架構”原創,轉載請註明出處。技術在於分享,我分享我快樂!如果本文對您有幫助,歡迎關注和點贊;如果您有任何建議也可留言評論或私信,您的支援是我堅持創作的動力。關注『 Tom彈架構 』可獲取更多技術乾貨!
- 使用橋接模式設計複雜的訊息系統
- 為什麼MySQL索引結構採用B 樹?
- 為什麼Netty執行緒池預設大小為CPU核數的2倍
- 談談你對深克隆和淺克隆的理解
- 什麼是代理,為什麼要用動態代理?
- 什麼是零拷貝,Netty是如何實現的?
- 3分鐘輕鬆理解單執行緒下的HashMap工作原理
- 被面試官問爛的Spring AOP原理,你是怎麼答的?
- Spring為何需要三級快取解決迴圈依賴,而不是二級快取?
- 為什麼Spring中每個Bean都要定義作用域?
- 談談你對Spring Bean的理解
- 趣談裝飾器模式,讓你一輩子不會忘
- 掌握這些招數,你也能寫出HR眼中的高分簡歷
- MongoDB高階應用之資料轉存與恢復(5)
- 圖解MongoDB叢集部署原理(3)
- 爆肝30天,肝出來史上最透徹Spring原理和27道高頻面試題總結
- Spring核心原理之IoC容器初體驗(2)
- Spring核心原理分析之MVC九大元件(1)
- 30個類手寫Spring核心原理之動態資料來源切換(8)
- 【緊急】Log4j又發新版2.17.0,只有徹底搞懂漏洞原因,才能以不變應萬變,小白也能看懂