单例模式
2019-03-26 本文已影响0人
Litch1
单例(Singleton)模式
非延迟加载的模式就不介绍了
说一下多线程下的延迟加载
简单加锁
就是在getInstance方法上面直接加上隐式锁
public static synchronized SingletonExample getInstance(){
if(null==instance){
instance = new SingletonExample();
}
return instance;
}
双重检查锁定
先来看看错误的写法
public static SingletonExample getInstance(){
if(null===instance)
synchronized(SingletonExample.class){
if(null=instance){
instance = new SingletonExample();
}
}
}
return instnce;
}
这个写法表面看起来很没有问题,先检查一遍,要是是null,就进入锁代码,这是要是有别的线程在new这个实例,那么就会等待,在进入临界区后,再进行一次判断。但是这个写法最大的问题就是,在判断的时候,若判断存在这个instance,就直接返回,但是这个instance,可能是其他线程已经还未初始化完毕的instance,这样就产生错误。
创建实例的操作有三个子操作
objRef=allocate(SingletonExample.class)
invokeConstructor(objRef);//初始化objRef的操作
instance = objRef
//在实际执行的时候,有可能重排序,导致先执行三,这个instance还没初始化完毕
所以这里为了保证程序的有序性,我们就必须使用volatile来修饰instance变量。
private static volatile SingletonExample instance;
public static SingletonExample getInstance(){
if(null===instance)
synchronized(SingletonExample.class){
if(null=instance){
instance = new SingletonExample();
}
}
}
return instnce;
}
静态内部类
使用内部类来保存外部类的唯一实例,这样在调用这个外部类的静态方法的时候,并不会将这个实例给初始化,只有在访问内部类时候,才会将内部类的类变量初始化,而且每个类的类变量只会初始化一次。
public class StaticSingletonExample{
private static class InstanceHolder{
final static StaticSingletonExample INSTANCE =new StaticSingletonExample();
}
public static StaticSingletonExample getInstance(){
return InstanceHolder.INSTANCE;
}
}
利用枚举类
枚举类型相当于一个单例类,他的字段相当于该类的唯一实例。相比于普通饿汉模式,这个的优点主要是可以自由序列化,以及代码比较简单,他可以保证单例,线程安全(枚举类本质上是一个final类,其中的枚举实例是final static的,构造方法是私有的,在一个static域中进行枚举实例的初始化)。
public static enum Singleton{
INSTANCE;
Singleton(){
//私有构造器
}
}