1、前言java
享元(FlyWeight)模式顧名思義,便是輕量級,緣由就是享元,共享元素,這裏的元素指的是對象。如何共享對象,那就是在檢測對象產生的時候,若是產生的是同一個對象,那麼直接使用已經產生的,聽起來很像單例模式,其實享元模式的內部實現就是很相似與單例模式的懶漢模式。享元的好處就是,在某些場景下能夠節省內存,從而使得程序的性能獲得提高。設計模式
那麼到底什麼對象能夠共享呢?好比操做系統安裝的時候就已經自動保存的圖標、字體等等,這些東西是能夠共享的,咱們能夠拿來直接使用,好比說Word上面的字體,這些都是享元,由於不會發生改變,屬於intrinsic(固定的、內在的、本質的),而有的對象是不能共享的,被稱爲extrinsic(外在的),本例之中本身使用txt文檔建立幾個字體,分別表示0,1,2...而後使用程序讀取這些字體生成一個對象,這樣的對象不能改變,所以能夠用來共享。學過計算機高級結構的都知道,共享的內存必定要保證一致性,發生改變的時候也同步更新,而這裏的享元從始至終沒有發生過改變,所以能夠做爲共享變量。數組
2、代碼多線程
BigChar類:(單個字符所表達的類)app
package zyr.dp.flyweight; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; public class BigChar { private char charname; private String frontData; public BigChar(char charname){ this.charname=charname; try { BufferedReader br=new BufferedReader(new FileReader("big"+charname+".txt")); StringBuffer sb=new StringBuffer(); String line; while((line=br.readLine())!=null){ sb.append(line+"\n"); } br.close(); frontData=sb.toString(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void print(){ System.out.println(frontData); } }
package zyr.dp.flyweight; import java.util.HashMap; public class BigCharFactory { private HashMap pool=new HashMap(); private static BigCharFactory bigCharFactory=new BigCharFactory(); private BigCharFactory(){ } public static BigCharFactory getInstance(){ return bigCharFactory; } public synchronized BigChar getBigChar(char name){ BigChar bigchar=(BigChar)pool.get(""+name); if(bigchar==null){ bigchar=new BigChar(name); pool.put(""+name, bigchar); } return bigchar; } public BigChar getBigCharNotUsed(char name){ return new BigChar(name); } }
package zyr.dp.flyweight; public class BigString { private BigChar [] bigchars; public BigString(String word,boolean isUsed){ if(isUsed == true){ bigchars=new BigChar[word.length()]; BigCharFactory bf=BigCharFactory.getInstance(); for(int i=0;i<word.length();i++){ bigchars[i]=bf.getBigChar(word.charAt(i)); } }else{ bigchars=new BigChar[word.length()]; BigCharFactory bf=BigCharFactory.getInstance(); for(int i=0;i<word.length();i++){ bigchars[i]=bf.getBigCharNotUsed(word.charAt(i)); } } } public void print(){ for(int i=0;i<bigchars.length;i++){ bigchars[i].print(); } } }
package zyr.dp.flyweight; public class Main { public static void main(String[] args) { String name="221100"; testMemory( name, false); testMemory( name, true); } public static void testMemory(String name,boolean isUsed){ System.out.println("是否使用輕量級:"+isUsed); BigString bs=new BigString(name,isUsed); bs.print(); countMemory(); System.out.println("================="); } public static void countMemory(){ Runtime.getRuntime().gc(); System.out.println("已使用內存:"+(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory())); } }
運行結果: 性能
是否使用輕量級:false ---****------ -------*----- --------*---- -----**------ ----*-------- --*******---- ---****------ -------*----- --------*---- -----**------ ----*-------- --*******---- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- ----*****---- ---*-----*--- --*-------*-- --*-------*-- ---*-----*--- ----*****---- ----*****---- ---*-----*--- --*-------*-- --*-------*-- ---*-----*--- ----*****---- 已使用內存:879440 ================= 是否使用輕量級:true ---****------ -------*----- --------*---- -----**------ ----*-------- --*******---- ---****------ -------*----- --------*---- -----**------ ----*-------- --*******---- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- -----**----- ----*****---- ---*-----*--- --*-------*-- --*-------*-- ---*-----*--- ----*****---- ----*****---- ---*-----*--- --*-------*-- --*-------*-- ---*-----*--- ----*****---- 已使用內存:876928 ================= 運行結果
3、總結字體
在咱們的程序中,使用了單例模式,同時爲了享元,咱們使用了相似於單例模式中的懶漢模式。加入synchronized是爲了防止多線程中出現誤入,固然在本例中是沒有多線程的,加不加鎖無所謂。同時,咱們對比了沒有使用享元的例子,(對比以前先啓動一次GC回收一次內存)能夠返現所佔用的內存空間,明顯使用了享元的佔用的內存小,而沒有使用享元的佔用內存多。而且這裏咱們要注意垃圾回收機制,在工廠類中,使用了hashmap來將bigchar對象保存起來,這樣就造成了一個DAC(有向無環圖),只要pool變量不被釋放,咱們使用的共享單元是不會被釋放的。這樣就保證了bigchar對象數組不被釋放,在使用享元模式的時候必定要特別注意這種狀況,由於垃圾回收器GC在內存佔用過多的時候被喚醒,而後清理那些被使用的內存,採用的方式就是DAC。this