淺談FlyWeight享元模式

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

 

淺談設計模式<最通俗易懂的講解>spa

相關文章
相關標籤/搜索