首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

JavaWeb 框架設計:自定義對象存儲池 ObjectPool 實現詳解

     編輯:Java 綜合教學

設計初衷與核心思路

在 JavaWeb 應用中,頻繁創建銷毀 Bean、DAO 等對象會帶來較大的 GC 壓力。為了解決這一問題,本文實現了一個基於單例模式的通用對象池 ObjectPool,支持對象的複用、定期清理與線程安全操作。

核心設計要點

  • 單例模式:全局唯一訪問入口,內部持有後台清理線程。
  • 接口規範:欲入池的類必須實現 AllowEnterObjectPool 接口,定義初始化與批量補充邏輯。
  • 雙映射結構:
    • hashMapForStorageObject:ClassName → List<Object>,按類別存儲對象實例,取放均操作 List 索引 0 位置(棧式)。
    • hashMapForObjectUsedTime:ClassName@ObjectHashCode → Integer,記錄對象被取出次數,作為清理依據。
  • 線程安全:所有公共方法均以 synchronized(this) 加鎖。
  • 定期清理:內部 clock 線程每 checkTime(預設 1 小時)掃描一次,若某類對象數量超過 minNumber(預設 30),則移除未被使用的對象並重置統計。

關鍵類與接口定義

AllowEnterObjectPool 接口

public interface AllowEnterObjectPool {
    ObjectPool objectPool = ObjectPool.getInstance();
    // 放入池前恢復默認狀態
    void initialMember();
    // 池中無可用對象時批量補充
    void batchAddSelf();
}

ObjectPool 核心實現(節選關鍵邏輯)

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();
            }
        }
    }
}

業務對象示例:Message 類

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);

優缺點分析與改進建議

  • 簡單易懂,無第三方依賴
  • 支持對象狀態重置與批量預熱
  • 定期清理防止內存洩漏
  • 全局鎖 synchronized(this) 並發性能差
  • 使用 ArrayList 索引 0 操作導致 O(n) 位移開銷
  • 清理邏輯遍歷全量數據,停頓時間不可控
  • 無對象驗證機制(如連接是否有效)
  • 硬編碼配置參數,缺乏靈活性
  • 替換為 ConcurrentHashMap + LinkedBlockingDeque 實現無鎖/細粒度鎖
  • 引入 Deque 實現 O(1) 入棧出棧
  • 採用分代/增量清理策略,或使用 ScheduledExecutorService 替代自定義線程
  • 增加 validateObject 回調,支持連接測試等
  • 外部化配置(最小/最大閒置數、清理間隔、存活時間等)
  • 或直接採用成熟框架:Apache Commons Pool 2、HikariCP(數據源)
  • 優點缺點/風險改進方向

    本實現適合作為教學演示或極簡場景使用。生產環境強烈建議採用經過充分驗證的成熟對象池庫,避免重複造輪子帶來的隱患。

    1. 上一篇文章:
    2. 下一篇文章:
    Copyright © 程式碼之家 All Rights Reserved