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

Java 享元模式深度解析:對象池技術與記憶體優化實戰

     編輯:Java 相關知識

模式定義與核心價值

享元模式:運用共享技術有效支持大量細粒度對象的復用,通過區分內部狀態 (可共享) 與 外部狀態 (不可共享),大幅減少對象創建數量,降低記憶體佔用。

結構角色

角色職責例子
Flyweight (抽象享元)定義接口,聲明外部狀態設置/獲取方法Shape 接口
ConcreteFlyweight (具體享元)實現接口,存儲內部狀態,實現業務邏輯Circle 類 (顏色為內部狀態)
UnsharedConcreteFlyweight (非共享享元)不要求共享的對象,可直接實例化大尺寸圖片、上下文對象
FlyweightFactory (享元工廠)管理享元池,提供獲取/創建享元的全局訪問點CircleFactory (Map<色彩, Circle>)
Client (客戶端)維護外部狀態,調用工廠獲取享元,調用享元操作繪圖程序主邏輯

經典實戰:圖形繪製系統

// 1. 抽象享元
interface Shape {
    void draw(int x, int y, int radius); // 外部狀態作為參數傳入
}

// 2. 具體享元:圓形 (顏色為內部狀態)
class Circle implements Shape {
    private final String color; // 內部狀態:不可變、可共享
    
    public Circle(String color) { this.color = color; }
    
    @Override
    public void draw(int x, int y, int radius) {
        System.out.printf("繪製 %s 圓:中心(%d,%d) 半徑%d%n", color, x, y, radius);
    }
    
    public String getColor() { return color; }
}

// 3. 享元工廠:管理色彩池
class ShapeFactory {
    private static final Map<String, Shape> pool = new ConcurrentHashMap<>();
    
    public static Shape getCircle(String color) {
        return pool.computeIfAbsent(color, Circle::new); // 線程安全獲取/創建
    }
    
    public static int getPoolSize() { return pool.size(); }
}

// 4. 客戶端使用
public class DrawingApp {
    private static final String[] COLORS = {"紅", "綠", "藍", "黃", "黑"};
    private static final Random random = new Random();
    
    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            String color = COLORS[random.nextInt(COLORS.length)];
            int x = random.nextInt(100);
            int y = random.nextInt(100);
            int radius = random.nextInt(50) + 10;
            
            Shape circle = ShapeFactory.getCircle(color); // 從池獲取
            circle.draw(x, y, radius); // 傳入外部狀態
        }
        System.out.println("實際創建對象數: " + ShapeFactory.getPoolSize()); // 輸出 ≤ 5
    }
}

JDK 內建享元應用

類享元對象內部狀態說明
String字符串常量字符序列字符串常量池 (String Pool),intern() 手動入池
Integer-128 ~ 127數值IntegerCache,valueOf() 自動復用
BooleanTRUE/FALSE布爾值單例模式實現
BigDecimal常用數值數值、精度valueOf() 緩存零值等
數據庫連接池Connection連接參數HikariCP、Druid 等池化技術本質是享元
線程池Thread線程屬性ExecutorService 復用線程避免頻繁創建銷毀

進階變體:複合享元

// 當單個享元粒度太細,可組合成複合享元
class CompositeShape implements Shape {
    private final List<Shape> shapes = new ArrayList<>();
    
    public void add(Shape shape) { shapes.add(shape); }
    
    @Override
    public void draw(int x, int y, int radius) {
        for (Shape s : shapes) s.draw(x, y, radius);
    }
}

// 工廠返回複合對象
class ShapeFactory {
    public static Shape getComposite(String... colors) {
        CompositeShape composite = new CompositeShape();
        for (String c : colors) composite.add(getCircle(c));
        return composite;
    }
}

適用性判斷清單

  • [ ] 應用程序使用大量相似對象
  • [ ] 對象佔用大量記憶體
  • [ ] 對象狀態可分為內部(共享)與外部(非共享)
  • [ ] 創建對象開銷大 (如資料庫連接、線程、大對象)
  • [ ] 系統不依賴對象身份 (即 a == b 不重要)

注意事項與代價

  • 線程安全:工廠獲取方法必須線程安全 (ConcurrentHashMap、雙重檢查鎖)
  • 外部狀態傳遞開銷:每次調用需傳遞外部狀態,增加參數傳遞成本
  • 邏輯複雜度上升:需區分內外部狀態,代碼理解難度增加
  • 生命周期管理:池對象何時釋放?需引用計數或弱引用 (WeakHashMap) 防止內存洩漏

總結

享元模式是空間換時間的經典體現。核心在於狀態分離:將不變的內部狀態封裝在共享對象中,將變化的外部狀態由客戶端管理並在調用時傳入。JDK 集合框架、包裝類緩存、連接池/線程池均是該模式的工業級應用。適用於大量細粒度對象且內存敏感的場景。

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