[我的设计模式] Singleton 单例模式

单例模式大概是最直观的一种设计模式了。尽管直观却不简单

数学与逻辑学中,singleton定义为“有且仅有一个元素的集合”。

单例模式可以如下定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供”。

我比较喜欢Design Patterns 一书中的描述"保证一个类仅有一个实例,并提供一个访问它的全局访问点"。

单例模式的特点  

1、单例类只能有一个实例。 

2、单例类必须自己自己创建自己的唯一实例。

3、单例类必须给所有其他对象提供这一实例。

最经典的实现

实现单例,可以将类的构造方法限定为private,避免在外部实例化,然后在类中提供一个静态的实例并能够返回给使用者,在同一个虚拟机范围内,Singleton的唯一实例
只能通过getInstance方法访问。

 

public class Singleton {



/**

* classic singleton

* realize lazy loaded 添加判断uniqueInstance是否初始化,实现了使用时才进行加载

*/

private static Singleton uniqueInstance=null;



private Singleton(){

//Exits only to defeat instantiation

}

public static Singleton getInstance(){

if(uniqueInstance==null){

uniqueInstance =new Singleton();

}

return uniqueInstance;

}

}

 

 

线程安全的实现

上面的实现方法并没有考虑多线程的环境,试想存在两个线程A和B,同时调用getInstance方法,线程A检查uniqueInstance是null,开始创建实例;同时线程B检测到
uniqueInstance是null,于是线程A/B各自创建了对象。
解决的最简单方法是加锁,为getInstance的静态方法添加synchronized关键字。但是考虑到Synchronized对性能影响较大(http://www.infoq.com/cn/articles/java-se-16-synchronized),
可以调整Synchronized添加(加锁)的位置。

public class SingletonSafed {



	/**

	 * 要在于instance = new Singleton()这句,这并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情。

	 * 给 instance 分配内存

	 * 调用 Singleton 的构造函数来初始化成员变量

	 * 将instance对象指向分配的内存空间(执行完这步 instance 就为非 null 了)

	 * 禁止指令重排序优化

	 */

	

	//这里初始化为null不是必须的,在Java里所有引用类型的静态以及实例成员,没有显式地初始化的,都会被设为null

	private volatile static SingletonSafed uniqueInstance=null;

	

	private SingletonSafed(){

		//私有的构造方法,防止外部实例化

	}

	

	//注意设置为静态方法

	public static SingletonSafed getInstance(){

		

		if(uniqueInstance== null){

			/**

			 * 同步块加锁。程序员称其为双重检查锁,因为会有两次检查 instance == null,一次是在同步块外,一次是在同步块内。

			 * 为什么在同步块内还要再检验一次?因为可能会有多个线程一起进入同步块外的 if,如果在同步块内不进行二次检验的话就会生成多个实例。

			 */

			synchronized(SingletonSafed.class){

				if(uniqueInstance== null){

					uniqueInstance= new SingletonSafed();					

				}

				

			}

		}

		    return uniqueInstance;

	}

}

  

饿汉式 懒汉式和登记式

另外,一些文档会提到单例模式的三种形式(懒汉式,饿汉式,登记式),其实饿汉式和懒汉式主要是线程安全的区别,同时懒汉式是延时加载,
在需要的时候才创建对象,而饿汉式在虚拟机启动的时候就会创建,上面已经提到,例如下面代码。
而登记式单例可以参考Spring创建Bean时的单例模式(http://blog.csdn.net/arvinrong/article/details/7756167)。

//饿汉式单例类.在类初始化时,已经自行实例化 

public class Singleton1 {

//私有的默认构造子

private Singleton1() {}

//已经自行实例化 

private static final Singleton1 single = new Singleton1();

//静态工厂方法 

public static Singleton1 getInstance() {

return single;

}

}

 

//懒汉式单例类.在第一次调用的时候实例化 

public class Singleton2 {

//私有的默认构造子

private Singleton2() {}

//注意,这里没有final 

private static Singleton2 single=null;

//静态工厂方法 

public synchronized static Singleton2 getInstance() {

if (single == null) { 

single = new Singleton2();

} 

return single;

}

}

  

这篇博客写的比我好,学习

如何正确地写出单例模式

你可能感兴趣的:(Singleton)