单例模式的实现方式总结

一、饿汉式

饿汉式----静态常量

//饿汉式-静态常量方式
class Singleton{
    //私有话构造器
    private Singleton(){}
    //给定一个私有的实例
    private static final Singleton singleton=new Singleton();
    //对外暴露一个接口
    public static Singleton getInstance(){
        return singleton;
    }
}

饿汉式---静态代码块方式

//饿汉式-静态代码块方式
class Singleton{
    private Singleton(){}
    private static final Singleton singleton;
    static {
        singleton=new Singleton();
    }

    public static Singleton getInstance(){
        return singleton;
    }
}

二、懒汉式

//懒汉式 --线程不安全 在单线程下使用,实现懒加载
class Singleton{
    private Singleton(){}
    private static Singleton singleton;

    public static Singleton getInstance(){
        if(singleton==null){
            singleton= new Singleton();
        }
        return singleton;
    }
}

三、双重检测锁机制

//双层检测所机制  线程安全,效率高,懒加载
class Singleton{
    private Singleton(){}

    private static Singleton singleton; //加volatile禁止指令重排

    public static Singleton getInstance(){
        if(singleton==null){
            synchronized (Singleton.class){
                if(singleton==null){
                    singleton=new Singleton();//可能会发生指令重排,造成空指针异常
                }
            }
        }
        return singleton;
    }

}

对singleton=new Singleton()这行代码进行分析,其实有三步:

  1. 在堆中申请一块内存地址

  2. 初始化内存对象singleton

  3. 将内存地址赋值给对象
    但在实际运行时,可能第二步和第三步的顺序发生变化,因为第二步和第三步都是依托于第一步的结果的,所以第一步不会重排。
    在多线程下,如果线程一进来执行完第一步再执行第三步时,此时线程二进来了,返回了对象。此时对象并未初始化,访问时就可能造成空指针异常。

    解决方案:加Volatile,禁止指令重排。

四、枚举方式

更简洁,自动支持序列化机制,绝对防止多次实例化。

//枚举方式
enum Singleton{
    INSTANCE;
}

验证

public static void main(String[] args) {
    Singleton instance = Singleton.getInstance();
    Singleton instance1 = Singleton.getInstance();
    System.out.println(instance == instance1);
    //Singleton singleton=Singleton.INSTANCE;
}
posted @ 2020-12-31 16:43  墨影笑倾城  阅读(68)  评论(0)    收藏  举报
Live2d Test Env