作者:Grey
原文地址:
享元模式是一種結構型模式。
一個應用場景是:運用共用技術有效地支援大量細粒度的物件。主要解決
在有大量物件時,有可能會造成記憶體溢位,我們把其中共同的部分抽象出來,如果有相同的業務請求,直接返回在記憶體中已有的物件,避免重新建立。
假設我們有一個子彈類,同時我們設計一個子彈池,子彈池負責提供子彈
public class BulletPool {
List<Bullet> bullets = new ArrayList<>();
{
for (int i = 0; i < 10; i++) {
bullets.add(new Bullet(true));
}
}
public Bullet getBullet() {
for (int i = 0; i < bullets.size(); i++) {
if (bullets.get(i).living) {
return bullets.get(i);
}
}
return new Bullet(true);
}
}
可以看到 getBullet 邏輯,如果池子中有子彈,就拿池中的子彈,如果沒有,就 new 一個新的子彈返回。
上述範例的 UML 圖如下
享元模式應用
對於開發者來說,垃圾回收是不可控的,而且是無法避免的。但是,我們還是可以通過一些方法來降低垃圾回收的頻率,減少程序暫停的時長。我們知道,只有使用過被丟棄的物件才是垃圾回收的目標,所以,我們需要想辦法在處理大量請求的同時,儘量少的產生這種一次性物件。最有效的方法就是,優化你的程式碼中處理請求的業務邏輯,儘量少的建立一次性物件,特別是佔用記憶體較大的物件。比如說,我們可以把收到請求的 Request 物件在業務流程中一直傳遞下去,而不是每執行一個步驟,就建立一個內容和 Request 物件差不多的新物件。這裡面沒有多少通用的優化方法。對於需要頻繁使用,佔用記憶體較大的一次性物件,我們可以考慮自行回收並重用這些物件。實現的方法是這樣的:我們可以為這些物件建立一個物件池。收到請求後,在物件池內申請一個物件,使用完後再放回到物件池中,這樣就可以反覆地重用這些物件,非常有效地避免頻繁觸發垃圾回收。
valueOf(boolean b)
方法 ,這個方法返回的 Boolean 物件不會新 new 出來,而是複用的同一個, 原始碼如下:public static Boolean valueOf(boolean b){
return(b?TRUE:FALSE);
}
public static final Boolean TRUE=new Boolean(true);
public static final Boolean FALSE=new Boolean(false);
Netty 中的 Buffer 分配。
連線池管理,例如:Apache Commons Pool
Java SE 中的 IntegerCache 類和 String 類
在 Java Integer 的實現中, -128 到 127 之間的整型物件會被事先建立好,快取在 IntegerCache 類中。當我們使用自動裝箱或者
valueOf()
來建立這個數值區間的整型物件時,會複用 IntegerCache 類事先建立好的物件。這裡的 IntegerCache 類就是享元工廠類,事先建立好的整型物件就是享元物件。在Java 中的 String 類的實現中,JVM 開闢一塊儲存區專門儲存字串常數,這塊儲存區叫作字串常數池,類似於 Integer 中的 IntegerCache 。不過,跟IntegerCache 不同的是,它並非事先建立好需要共用的物件,而是在程式的執行期間,根據需要來建立和快取字串常數。
注:Java 提供了兩個設定 IntegerCache 的引數
//方法一:
-Djava.lang.Integer.IntegerCache.high=255
//方法二:
-XX:AutoBoxCacheMax=255
本文來自部落格園,作者:Grey Zeng,轉載請註明原文連結:https://www.cnblogs.com/greyzeng/p/16880631.html