设计模式之单件模式

来源:互联网 发布:日本语言翻译软件 编辑:程序博客网 时间:2024/06/05 14:49

有一些对象我们只需要一个(也只能有一个)比如:线程池、cache、对话框、处理偏好设置和注册表的对象、日志对象、充当打印机、显卡等设备的驱动程序的对象。

利用静态类变量、静态方法和适当的访问修饰符,就可以做到只存在一个实例。

这是一个经典的单件模式:

public class Singleton {private static Singleton uniqueInstance;private Singleton(){}public static Singleton getInstance(){if(uniqueInstance==null)   uniqueInstance=new Singleton();return uniqueInstance;   }//静态方法,引用要使用类名}

单件模式确保一个类只有一个实例,并提供一个全局访问点。

它比全局变量多了一个优点:延迟实例化


一个巧克力工厂具有计算机控制的巧克力锅炉,只能存在一个锅炉,不然会有bad things 发生:

public class ChocolateBoiler {private boolean empty;private boolean boiled;private static ChocolateBoiler uniqueInstance;private ChocolateBoiler(){empty=true;boiled=false;}public static ChocolateBoiler getInstance(){if(uniqueInstance==null)uniqueInstance=new ChocolateBoiler();return uniqueInstance;}public void fill(){if(isEmpty()){empty=false;boiled=false;}}public void drain(){if(!isEmpty() && isBoiled())empty=true;}public void boil(){if(!isEmpty() && !isBoiled())boiled=true;}public boolean isEmpty(){return empty;}public boolean isBoiled(){return boiled;}}

但是,当我们执行以下代码时,就会发生麻烦,竟然允许在加热的过层中加入原料:

ChocolateBoiler boiler=ChocolateBoiler.getInstance();

fill();

boil();

drain();


这里有两个线程要执行这段代码,我们检查getInstance()方法中的操作次序和uniqueInstance的值就会发现,它们重叠了,产生了两个锅炉对象。


处理多线程,只要把getInstance()方法变成同步方法,可以解决:

public static synchronized ChocolateBoiler getInstance(){if(uniqueInstance==null)uniqueInstance=new ChocolateBoiler();return uniqueInstance;}

但是同步会降低性能。。。

当getInstance()的性能对应用程序不是很关键,就什么都别做。这是最直接可行的做法!

otherwise,使用急切创建实例,而不用延迟实例化的方法:

public class ChocolateBoiler {private boolean empty;private boolean boiled;private static ChocolateBoiler uniqueInstance=new ChocolateBoiler();private ChocolateBoiler(){empty=true;boiled=false;}public static  ChocolateBoiler getInstance(){return uniqueInstance;}//...}


加载这个类时马上创建此唯一的单件实例。

还有一种更好的:双重检查加锁

原理是这样的,首先检查是否实例已经被创建,如果尚未创建,才进行同步。这样一来,只有第一次会同步!!!

public class ChocolateBoiler {private boolean empty;private boolean boiled;private static volatile ChocolateBoiler uniqueInstance;private ChocolateBoiler(){empty=true;boiled=false;}public static  ChocolateBoiler getInstance(){if(uniqueInstance==null){synchronized (ChocolateBoiler.class) {if(uniqueInstance==null)uniqueInstance=new ChocolateBoiler();}}return uniqueInstance;}//...}

其中volatile关键词确保当uniqueInstance变量被初始化成Singleton实例时,多个线程正确处理uniqueInstance变量。

这个方法在对性能要求高的时候可以用,不然就是杀鸡用牛刀了,呵呵。

0 0
原创粉丝点击