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