浅尝设计模式——如何使用单件模式

本文为阅读《Head First 设计模式》一书的摘要总结

单件模式

定义

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

浅尝设计模式——如何使用单件模式_第1张图片

示例

public class Singleton{
     
	private static Singleton uniqueInstance;

	private Singletion(){
     
		uniqueInstance = new Singleton();
	}

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

上面的例子中,Singleton类的构造器的访问修饰符为private,这意味着我们不能在其他对象中通过new操作符来实例化这个对象。另外提供了一个静态的getInstance方法,该方法通过判断静态变量uniqueInstance是否为空来觉得是否实例化Singleton对象。我们通过调用getInstance方法,就可以得到Singleton单件。

在单线程应用中上面的代码没有问题,但是在多线程应用中,可能就会出现问题了。

在多线程应用中,假设Singleton还没有创建实例。现在线程1调用getInstance方法,当通过判断uniqueInstance==null之后,在实例化对象之前被剥夺了CPU,线程2开始调用getInstance,并获得了Singleton实例。当线程2被剥夺CPU之后,线程1继续执行,此时,uniqueInstace将会引用新的实例。

为了解决这个问题,我们只需要将getInstance改为同步方法:

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

这样,每次调用getInstance方法,都需要等待其他线程退出该方法之后,当前线程才能进入该方法。但是这便降低了性能。实际是,该方法只有第一次执行时需要同步,一旦设置好uniqueInstace变量的引用,就不需要同步这个方法了。

  • 若是应用程序可以忍受同步带来的效率下降,那么我们就可以不用做任何修改
  • 前面的例子采用的是延迟实例化,我们可以采用 预实例化,来消除多线程带来的问题:
public class Singleton{
     
	private static Singleton uniqueInstance = new Singleton();

	private Singletion(){
     }

	public static Singleton getInstance(){
     
		return uniqueInstance;
	}
}
  • 双检查加锁:如果十分关注性能,该方法能大大减少getInstance的耗时。
public class Singletion{
     
	private volatile static Singletion uniqueInstance;

	private Singleton(){
     

	}

	public static Singleton getInstance(){
     
		if (uniqueInstace == null){
     
			synchronized(Singletion.class){
     
				if (uniqueInstance == null){
     
					uniqueInstace = new Singleton();
				}
			}
		}
		return uniqueInstace;
	}
}

你可能感兴趣的:(设计模式)