单例设计模式的七种方式

单例是一种设计模式,指该类被创建后有且仅有一个实例供外部访问,并且提供一个全局的访问入口。
有三个核心点:
1、类的构造方法私有化
2、内部产生该类的实例化对象,并声明为private static
3、定义一个静态方法返回该类的实例
常见的单例模式有下面几种。
一、饱汉方式
public class Singleton {
	private static Singleton singleton;
	private Singleton(){}
	public static Singleton  getInstance(){
		if(singleton == null){
			singleton = new Singleton ();
		}
		return singleton;
	}
}
该方式不能算真正的单例模式,在多线程环境下根本无法实现单实例。
 
 
二、饱汉-线程安全
public class Singleton {
private static Singleton singleton;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
 
实现了线程的同步,但是synchronized 的粗暴导致该方式性能低下。
 
三、饿汉方式
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton (){}
public static Singleton getInstance(){
return singleton;
}
}
 
所谓饿汉即一开始就声明示例,是通过类加载的方式避免了多线程同步问题。在类初始化是实例化singleton。
 
四、饿汉-静态代码块
public class Singleton {
private static Singleton singleton;
private Singleton(){}
static{
singleton = new Singleton();
}
public static Singleton getInstance(){
return singleton;
}
}
 
在编码上跟饿汉方式有很大区别,但是实际区别不大,都是在类初始化时候实例化singleton。
 
五、静态内部类
public class Singleton {
private Singleton(){}
private static class SingletonHolder {
private static final Singleton singleton = new Singleton();
}
public static final Singleton getInstance(){
return SingletonHolder.singleton;
}
}
 
该方式也是利用classloader保证単实例,但是跟饿汉模式还是有很大区别的,饿汉是在类初始化时候已经实例化了singleton,但是静态内部类只有在真正调用getInstance()时候才会实例化singleton,故真正意义上实现了懒加载。
 
六、双重校验
public class Singleton {
private volatile  static Singleton singleton ;
private Singleton(){}
public static Singleton getInstance(){
if(singleton == null){
synchronized (Singleton.class) {
if(singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
 
该方式是饿汉-线程安全方式的变种,且大大提高了性能。但是请注意写法使用了volatile  关键字,为什么?主要还是跟JVM的制令重排有关系,导致线程获取未完全初始化的实例。
singleton = new Singleton(); 的过程经历了三个步骤。
1、在堆中为Singleton开辟内存空间,分配地址。
2、执行构造函数初始化
3、将内存地址赋值给singleton 。
如果是经过了指令重排后,那么2、3步骤将交换。试想如果在执行完步骤3,还未开始执行2,另外的线程在执行到第一个if判断是,此时的singleton != null,那么将返回一个外完全初始化的singleton。
七、枚举方式
public enum Singleton {
	
	INSTANCE;
	
	private String toDO(){
		return "XXXX";
		
	}
}
关于枚举实现单例,这篇文章解释的很详细http://www.cnblogs.com/ldq2016/p/6627542.html。
就个人而言:
 第一种饱汉模式根本就不能算是单例,三、四基本是一样。五、六很经典。三、五是比较常用的。枚举模式好处还是多多的,就是平时用的很少而已。
 
 

 

猜你喜欢

转载自qiguanjiaduobao.iteye.com/blog/2370324