单例模式

单例(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(){
        //私有构造器
    }
}

你可能感兴趣的:(单例模式)