设计模式之单件模式

有一些对象我们只需要一个(也只能有一个)比如:线程池、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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值