目录

饿汉式单例

public class Singleton {
    private static Singleton instance = new Singleton();
    public static Singleton getInstance() {
        return instance;
    }
}

饿汉式单例,在类第一次加载的时候,单例就完成了初始化,是线程安全的。

懒汉式单例

public class Singleton {
    private static Singleton instance = null;
    public static Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

懒汉式单例,运用了延迟加载,在需要的时候进行初始化。

但多线程下有两个问题:

  1. 可能会得到不同的实例
  2. 可能得到一个尚未初始化完全的对象

怎样修改懒汉式单例才能保证线程安全性呢?

DCL+ volatile

DCL 即双重检查锁定机制

// 尝试一:锁可以保证线程安全性,但并发的情况下阻塞会导致效率低
public class Singleton {
    private static Singleton instance = null;
    synchronized public static Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

// 尝试二:缩小同步块的范围,有助于提高效率,但效果微乎其微
public class Singleton {
    private static Singleton instance = null;
    public static Singleton getInstance() {
        synchronized (Singleton.class) {
            if (instance == null) {
                instance = new Singleton();
            }
        }
        return instance;
    }
}

// 尝试三:继续缩小同步块的范围,效率明显提升,但得到的可能不是单例
public class Singleton {
    private static Singleton instance = null;
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                instance = new Singleton();
            }
        }
        return instance;
    }
}

// 尝试四:DCL,第一次空值检测对提升性能起到了很大的作用,但可能得到一个尚未初始化完全的对象
public class Singleton {
    private static Singleton instance = null;
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

// 尝试五:在 DCL 基础上,为变量 instance 加上 voltile 关键字
public class Singleton {
    private volatile static Singleton instance = null;
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

voltile 禁止了指令级并行的《重排序》,保证了初始化安全性。

懒汉式单例,使用 DCL + volatile,才具有线程安全性。

DCL + final

前面的初始化不安全,指的是尚未给普通属性分配内存就调用到它了。

此时,用 final 关键字修饰这些普通属性同样能解决问题,《final 域的内存语义提供了初始化安全保证

public class Singleton {
    private static Singleton instance = null;
    private final int para;
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
    private Singleton(){
        para = 1;
    }
}

静态内部类实现单例模式

public class Singleton {
    private static class Holder{
        private static Singleton instance = new Singleton();
    }
    public static Singleton getInstance() {
        return Holder.instance;
    }
}

调用 getInstance 方法导致 Holder 类被加载,加载过程中初始化了单例。

而类的加载是加锁的,加载完成后才能加载另一个类,因此能够保证单例模式的安全性。

同时具有延时加载的特性。

版权声明:本文为xmsx原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/xmsx/p/9752595.html