設計模式_享元模式

Flyweight Pattern 

    use sharing to support large unmbers of fine-grained objects efficiently(使用共享對象可有效地支持大量的細粒度的對象)


例子

“三哥,廠商人員已經定位出了,OutOfMemory內存溢出,沒查到有內存泄漏的情況,現 在還在跟蹤……是突然暴漲的,都是在繁忙期出現問題的……” 
內存溢出對Java應用來說實在是太平常了,有以下兩種可能。
● 內存泄漏
無意識的代碼缺陷,導致內存泄漏,JVM不能獲得連續的內存空間。
● 對象太多
代碼寫得很爛,產生的對象太多,內存被耗盡。現在的情況是沒有內存泄漏,那只有一 種原因——代碼太差把內存耗盡。

系統廠商提供的分析報告,報告中指出:內存 突然由800MB飆升到1.4GB,新的對象申請不到內存空間,於是出現OutOfMemory,同時報 告中還列出宕機時刻內存中的對象,其中SignInfo類的對象就有400MB。

“三哥,這是很正常的,這麼大的訪問量,產生出這麼多的SignInfo對象也是應該的,內 存中有這麼多對象並不表示這些對象正在被使用呀,估計很大一部分還沒有被回收而已,垃 圾回收器什麼時候回收內存中的對象這是不確定的。你看,併發200多個,這可是併發數量……”


public class SignInfo {
 private String key;
 private String id;
 private String subject;
 private String location;
 public String getSubject() {
  return subject;
 }
 public void setSubject(String subject) {
  this.subject = subject;
 }
 public String getLocation() {
  return location;
 }
 public void setLocation(String location) {
  this.location = location;
 }
 public String getKey() {
  return key;
 }
 public void setKey(String key) {
  this.key = key;
 }
 public String getId() {
  return id;
 }
 public void setId(String id) {
  this.id = id;
 }
}


public class SignInfoFactory {
 
 private static HashMap<String,SignInfo> pool=new HashMap<String,SignInfo>();
 
 public static SignInfo getSignInfo(String key){
  SignInfo result=null;
  if(!pool.containsKey(key)){
   System.out.println(key+"-------------建立對象,並放到池中");
   result=new SignInfo();
   pool.put(key, result);
  }else{
   result=pool.get(key);
   System.out.println(key+"---------------直接從池中取");
  }
  return result;
 }
}


小知識

在對象池中,對象一旦產生,必然有一個唯一的、可訪問的狀態標誌該對象,而 且池中的對象聲明週期是由池容器決定,而不是由使用者決定的。
以String類型作爲外部狀態到對象池取對象,而爲什麼不抽取出倆個屬性,例如id和location放到一個類中,然後以這個類作爲外部狀態,重寫equals方法和hashcode方法(如果把一個對象作爲Map類的鍵值,一定要確保重寫了equals和hashCode方法, 否則會出現通過鍵值搜索失敗的情況,例如map.get(object)、map.contains(object)等會返回失敗的結果。)
這樣做的後果是效率降低,因爲外部狀態最好以java基本類型作爲標誌,例如String,int等,可以大幅度提升效率。


public class Client {
 public static void main(String[] args) {
  String state1="sub1shanghai1";
  String state2="sub1shanghai2";
  String state3="sub1shanghai2";
 
  SignInfoFactory.getSignInfo(state1);
  SignInfoFactory.getSignInfo(state2);
 
  long start=System.currentTimeMillis();
  for(int i=0;i<100000;i++){
   SignInfoFactory.getSignInfo(state3);
  }
  long end=System.currentTimeMillis();
  System.out.println("total time:"+(end-start)+"ms");
 }
}


注意
其他問題還有線程安全,性能平衡等等,需要經驗,這個東西只是提供一個方向,需要是還是實際開發。

不得不說這是個好東西,但是實際中,需要考慮的東西很多,這個爲了解決一些連接問題根據底層硬件以及環境而做出的最好行動,還是需要看背景和實際問題。

我是菜鳥,我在路上。

發佈了78 篇原創文章 · 獲贊 17 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章