单例模式介绍:
单例是应用中最广泛的模式之一,在应用这个模式时,单例对象的类必须只有一个实例存在。
1.饿汉模式
public class Singleton {
public static final Singleton singleton= new Singleton();
private Singleton() {}
public static Singleten getSingleton(){
return singleton;
}
}
2.懒汉模式
public class Singleton{
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance(){
if( instance == null){
instance = new Singleton();
}
return instance;
}
}
getInstance()方法中添加了synchronized关键字,也就是说getInstance是一个同步方法,这就是所说的在多线程情况下保证单例对象唯一性的手段。
缺点:每次调用getInstance方法都会进行同步,这样会消耗不必要的资源,也是懒汉模式最大的问题,并且第一次加载的时进行实例化,反应稍慢。这种模式一般不建议使用。
3.Double check lock ( DLC )实现单例
优点:既能在需要的时候才初始化单例,又能保证现成安全,且单例对象初始化后调用getInstance不进行同步锁。
缺点:第一次加载时反应稍慢,也由于Java内存模型偶而会失败。在高并发的情况下也有一定的缺陷,虽然发生继续很小,DCL是使用最多的单例凡是
public class Singleton{
private static Singleton sInstance = null ;
private Singleton(){}
public void doSomesing(){
System.out.println("do sth.");
}
public static Singleton getInstace(){
if( sunspace == null ){
synchronized( Singleton.class){
if(sInstance == null){
sInstace = new Singleton();
}
}
}
return sInstance;
}
}
第一层判null判断主要是为了不必要的同步,
第二层的判断是为了在null的情况下穿件实例。
这是什么意思呢?我们来分析一下
假设现成A执行 sInstance = new Singleton();语句,这里看着是一句代码,但实际上并不是一个院子操作,这句代码最终会被编译成多条汇编指令,大致他做了3件事:
1.给Singleton的实例分配内存;
2.调用Singleton()的构造函数,初始化成员字段;
3.将sInstance对象指向分配的内存空间(sInstance就不是null )
但是,由于Java编译器允许处理器乱序执行,执行的顺序可能是1-2-3也坑你1-3-2。如果后者并且在3执行完毕2未执行之前,就被切换到另一个现成,这时候sInstance已经执行过3已经部位null了后来现成直接取回sInstance,在使用时会出错,这就是DCL失效问题,二期这种难以跟踪的问题会隐藏很久。