单例模式

创建型模式

单例模式

该模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象

优点

缺点

使用场景

单例模式按加载顺序又可分为饿汉模式,懒汉模式

饿汉式

class HungrySingleTon {
    private HungrySingleTon(){}

    private static HungrySingleTon hungrySingleTon = new HungrySingleTon();

    public static HungrySingleTon getInstance() {
        return hungrySingleTon;
    }
}

懒汉式

class lazySingleTonOfDcl {
    private lazySingleTonOfDcl(){}
    // volatile 关键字,限制cpu对指令重排序
    private static volatile lazySingleTonOfDcl singleTon = null;

    public static lazySingleTonOfDcl getInstance() {
        if (singleTon == null) {
            synchronized (lazySingleTonOfDcl.class) {
                if (singleTon == null) {
                    singleTon = new lazySingleTonOfDcl();
                }
            }
        }
        return singleTon;
    }
}

在懒加载单例对象时候,由于Java中new一个对象并不是一个原子操作,编译时singleton = new Singleton(); 语句会被转成多条汇编指令,它们大致做了3件事情

由于Java编译器允许处理器乱序执行(处理器会根据语句执行效率进行指令重排序),以及JDK1.5之前的旧的Java内存模型中Cache、寄存器到主内存回写顺序的规定,上面步骤2)和3)的执行顺序是无法确定的,可能是 1) → 2) → 3) 也可能是 1) → 3) → 2) 。如果是后一种情况,在线程 A 执行完步骤 3) 但还没完成 2) 之前,被切换到线程 B 上,此时线程 B 对singleton 第1次判空结果为false,直接取走了singleton使用,但是构造函数却还没有完成所有的初始化工作,就会出错,也就是DCL失效问题。这时我们在加上volatile关键字就能解决这个问题

另外还有其他实现单例模式的方式,如下图 此处输入图片的描述