单例模式

Posted xmsx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例模式相关的知识,希望对你有一定的参考价值。

目录

饿汉式单例

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,才具有线程安全性。

静态内部类实现单例模式

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

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

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

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

以上是关于单例模式的主要内容,如果未能解决你的问题,请参考以下文章

常用代码片段

性能比较好的单例写法

片段作为 Android 中的单例

单例片段或保存网页视图状态

你熟悉的设计模式都有哪些?写出单例模式的实现代码

单例模式以及静态代码块