快捷搜索: 王者荣耀 脱发

单例模式(饿汉式,dcl懒汉式)

饿汉式单例

//单例模式,一般用于比较大,复杂的对象,只初始化一次,应该还有一个private的构造函数,使得不能用new来实例化对象,只能调用getInstance方法来得到对象,
// 而getInstance保证了每次调用都返回相同的对象。
//饿汉式单例
//饿汉式就是一上来就把对象加载了,不管是否被使用,饿汉式会造成资源浪费
public class Hungry {
    //单例模式最重要的是构造器私有化
    private  Hungry(){

    }
    private  final  static  Hungry HUNGRY=new Hungry();
    public  static Hungry getInstance(){
        return  HUNGRY;
    }
}

懒汉式单例

//懒汉式单例
public class Lazy {
    private  Lazy(){
        System.out.println(Thread.currentThread().getName()+"ok");

    }

    private  static  Lazy lazy;

    public  static  Lazy getInstance(){
                if (lazy == null) {
                    lazy = new Lazy();
                }
            
        
        return  lazy;
    }
}

//模拟多线程测试
    public static void main(String[] args) {
        for(int i=0;i<10;i++){
            new Thread(()->{
                Lazy.getInstance();
            }).start();
        }
    }

打印输出了十条语句,出现了线程安全问题!

多线程情况下,多个线程同时执行到 if(lazy==null)语句,创建多个引用对象。

解决方法,双重检验锁

//懒汉式单例
public class Lazy {
    private  Lazy(){
        System.out.println(Thread.currentThread().getName()+"ok");

    }

    private  static  Lazy lazy;

    public  static  Lazy getInstance(){
        if(lazy==null) {
            synchronized (Lazy.class) {
                if (lazy == null) {
                    lazy = new Lazy();
/**
                     * 不是原子性操作
                     * 1. 分配内存空间
                     * 2. 执行构造方法 初始化对象
                     * 3. 把对象指向 内存空间
                     *
                     * 会进行指令重排
                     * A 线程的执行顺序可能是1 3 2
                     *   当A 执行完3 还没执行2的时候  线程B进来执行  由于执行完3 会认为 
                         lazy
                     *   不为null(因为已经指向了内存空间) 所以B会返回未完成构造的lazy
                     *   需要在lazy上加volatile修饰
                     */

                }
            }
        }
        return  lazy;   //lazy可能还未完成构造,它的空间是虚无的。
    }
}

此方法会造成指令重排序。

volatile关键字作用:

    保证可见性(变量都在主存进行操作) 禁止指令重排序,建立内存屏障; 不能保证原子性。
private  static volatile Lazy lazy;

最终版 高性能,安全,懒汉式

public class Lazy {
    private  Lazy(){}

    private  static volatile Lazy lazy;

    public  static  Lazy getInstance(){
        if(lazy==null) {
            synchronized (Lazy.class) {
                if (lazy == null) {
                    lazy = new Lazy();
                }
            }
        }
        return  lazy;
    }
}
经验分享 程序员 微信小程序 职场和发展