在 JavaWeb 應用中,頻繁創建銷毀 Bean、DAO 等對象會帶來較大的 GC 壓力。為了解決這一問題,本文實現了一個基於單例模式的通用對象池 ObjectPool,支持對象的複用、定期清理與線程安全操作。
AllowEnterObjectPool 接口,定義初始化與批量補充邏輯。hashMapForStorageObject:ClassName → List<Object>,按類別存儲對象實例,取放均操作 List 索引 0 位置(棧式)。hashMapForObjectUsedTime:ClassName@ObjectHashCode → Integer,記錄對象被取出次數,作為清理依據。synchronized(this) 加鎖。clock 線程每 checkTime(預設 1 小時)掃描一次,若某類對象數量超過 minNumber(預設 30),則移除未被使用的對象並重置統計。public interface AllowEnterObjectPool {
ObjectPool objectPool = ObjectPool.getInstance();
// 放入池前恢復默認狀態
void initialMember();
// 池中無可用對象時批量補充
void batchAddSelf();
}
public class ObjectPool implements Debug, Assistant {
private int minNumber = 30;
private int checkTime = 60 * 60 * 1000; // 1小時
private HashMap<String, ArrayList> hashMapForStorageObject = new HashMap<>();
private HashMap<String, Integer> hashMapForObjectUsedTime = new HashMap<>();
private static ObjectPool objectPool = new ObjectPool();
private ObjectPool() { new clock().start(); }
// 取出對象:優先復用,無則創建並觸發批量補充
public <T> T takeOut(Class<T> object) {
synchronized (this) {
String className = object.getName();
ArrayList<T> objectList = hashMapForStorageObject.get(className);
if (objectList == null || objectList.size() == 0) {
// 創建新實例並調用 batchAddSelf 批量補充
T createObject = object.newInstance();
Method m = object.getMethod("batchAddSelf");
m.invoke(createObject);
if (objectList == null) {
objectList = new ArrayList<>();
hashMapForStorageObject.put(className, objectList);
}
objectList.add(createObject);
}
T returnObject = objectList.remove(0); // 棧頂取出
// 記錄使用次數
String flag = className + "@" + Integer.toHexString(returnObject.hashCode());
hashMapForObjectUsedTime.merge(flag, 1, Integer::sum);
return returnObject;
}
}
// 歸還對象:恢復狀態後放入棧頂
public synchronized void put(AllowEnterObjectPool obj) {
obj.initialMember();
String className = obj.getClass().getName();
ArrayList list = hashMapForStorageObject.computeIfAbsent(className, k -> new ArrayList());
list.add(0, obj);
}
// 定期清理:移除未使用對象,重置統計
public synchronized void clearObject() {
for (String key : hashMapForStorageObject.keySet()) {
ArrayList list = hashMapForStorageObject.get(key);
if (list.size() < minNumber) continue;
for (int i = 0; i < list.size(); i++) {
Object obj = list.get(i);
String flag = key + "@" + Integer.toHexString(obj.hashCode());
if (hashMapForObjectUsedTime.get(flag) == null) {
list.remove(i--);
hashMapForObjectUsedTime.remove(flag);
if (list.size() == minNumber) break;
}
}
}
hashMapForObjectUsedTime.clear();
}
// 內部清理線程
private class clock extends Thread {
public void run() {
while (true) {
try { Thread.sleep(checkTime); } catch (InterruptedException e) { e.printStackTrace(); }
clearObject();
}
}
}
}
public class Message implements AllowEnterObjectPool {
private String name; private int age;
public void initialMember() { name = ""; age = 0; }
public void batchAddSelf() {
for (int i = 0; i < 10; i++)
objectPool.put(new Message());
}
// getter/setter 略
}
// 獲取對象
Message msg = ObjectPool.getInstance().takeOut(Message.class);
msg.setName("Test"); msg.setAge(25);
// 業務處理...
// 歸還對象
ObjectPool.getInstance().put(msg);
| 優點 | 缺點/風險 | 改進方向 |
|---|
本實現適合作為教學演示或極簡場景使用。生產環境強烈建議採用經過充分驗證的成熟對象池庫,避免重複造輪子帶來的隱患。