美文网首页
单例模式的实现

单例模式的实现

作者: tuacy | 来源:发表于2018-07-03 16:33 被阅读48次

       单例模式估计是咱们碰到最多也是最简单的一种设计模式了(也是面试中经常会遇到的面试题)。单例模式保证一个类只有一个实例,比如咱们在Android应用中登入成功之后保存用户信息就会优先考虑单例模式。

       单例模式有六种常规的写法:饿汉式、懒汉式(线程不安全)、懒汉式(线程安全)、DCL双重校验模式、静态内部类、枚举。

一、饿汉式

       饿汉式,有两种不同的写法:静态常量、静态代码块。

       饿汉式-静态常量

public class Singleton {

    private Singleton() {
    }

    /**
     * 静态常量
     */
    private final static Singleton INSTANCE = new Singleton();

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

       饿汉式-静态代码块

public class Singleton {

    private Singleton() {
    }

    /**
     * 静态代码块
     */
    private static Singleton INSTANCE;
    static {
        INSTANCE = new Singleton();
    }

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

       饿汉式实现单例有两种方式:静态常量、静态代码块。两种写法不管是在性能上还是在效果上都是一样的,都是在类装载的时候完成实例化。类装载的时候JVM保证了线程安全。

       特点:没有懒加载(类装载的时候就初始化)、线程安全。不推荐使用

二、懒汉式(线程不安全)

public class Singleton {

    private Singleton() {
    }

    private static Singleton INSTANCE;

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

       这种写法在单线程的程序中没啥问题,在第一次调用getInstance()方法的时候创建实例(懒加载)。但是在多线程的情况下多个线程同时调用getInstance()函数的时候在同一时刻这些线程都通过了if (INSTANCE == null)的判断,那就有可能重复创建了多个实例了。

       特点:懒加载(getInstance的时候才初始化)、线程不安全。不推荐使用

三、懒汉式(线程安全)

public class Singleton {

    private Singleton() {
    }

    private static Singleton INSTANCE;

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

       这种写法给getInstance()方法添加了synchronized,告诉JVM这是个同步方法。当多个线程同时调用getInstance()方法时,同一时刻只能有一个线程通过getInstance()方法,其他的线程只能等待。所以这种方式效率相对来说比较低。

       特点:懒加载(getInstance的时候才初始化)、线程安全、效率低(多个线程同时getInstance的时候会有等待的情况)。不推荐使用

懒汉式里面的懒字是懒加载的懒。为了和饿汉式对应有的地方也把懒汉式叫做饱汉式。

四、DCL双重校验模式(推荐)

public class Singleton {

    private Singleton() {
    }

    private volatile static Singleton INSTANCE;

    public static Singleton getInstance() {
        if (INSTANCE == null) { //第一次校验
            synchronized (Singleton.class) {
                if (INSTANCE == null) { //第二次校验
                    INSTANCE = new Singleton();
                }
            }
        }
        return INSTANCE;
    }
}

       这种写法在懒汉式(线程安全)方式之上做了进一步的提高。进行了两次if (INSTANCE == null)检查:第一次判断是为了避免不必要的同步从而提高效率、第二次判断之前添加了synchronized同步代码块保证了同一时刻只有一个线程能进来创建实例。

       特点:懒加载、线程安全、效率高。推荐使用

五、静态内部类(推荐)

public class Singleton {

    private Singleton() {
    }

    /**
     * 静态内部类
     */
    private static class SingletonInstance {

        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

       这种实现方式在Singleton类被装载时并不会实例化,只有在第一次调用getInstance()方法的时候才会装载内部类SingletonInstance从而完成Singleton的初始化,JVM保证了在类进行初始化时,别的线程是无法进入的。所以静态内部类实现单例的方法是线程安全的。而且还起到了懒加载的作用。

       特点:懒加载、线程安全。推荐使用

六、枚举(推荐)

       枚举可以有自己的属性,也可以有自己的方法。

       第一种写法(代码简洁,强烈推荐):

这里我假设mUserName来我要在单例里面保存的一个属性,之后我们可以通过SingletonEnum.INSTANCE.getUserName();来操作单例里面的属性。

public enum SingletonEnum {
    INSTANCE;

    private String mUserName;

    public String getUserName() {
        return mUserName;
    }

    public void setUserName(String userName) {
        mUserName = userName;
    }
}

       第二种写法,我们额外的多一个Singleton类,Singleton类里面放我们单例要保存的一些信息。调用的时候通过SingletonEnum.INSTANCE.getInstance()获取到Singleton类:

额外的Singleton类

public class Singleton {

}
public enum SingletonEnum {
    INSTANCE;

    private Singleton instance;

    SingletonEnum() {
        instance = new Singleton();
    }

    public Singleton getInstance() {
        return instance;
    }
}

       枚举实例JVM保证了线程安全,并且在任何情况下,它都是一个单例。同时枚举也是在第一次使用的时候初始化,这样也保证了懒加载。

       特点:懒加载、线程安全。推荐使用


       综上所述,综合效率,安全等因素对于单例模式实现的选择,我们优先推荐枚举(代码简洁),其次静态内部类,最后是DCL双重校验模式。

相关文章

  • Android设计模式总结

    单例模式:饿汉单例模式://饿汉单例模式 懒汉单例模式: Double CheckLock(DCL)实现单例 Bu...

  • 单例模式

    一、实现单例模式 或者 二、透明的单例模式 三、用代理实现单例模式 四、JavaScript中的单例模式 在Jav...

  • python面试题-2018.1.30

    问题:如何实现单例模式? 通过new方法来实现单例模式。 变体: 通过装饰器来实现单例模式 通过元类来创建单例模式...

  • 单例模式之枚举类enum

    通过枚举实现单例模式 枚举类实现单例模式的优点 对于饿汉式单例模式和懒汉式单例模式了解的同学,使用以上两种单例模式...

  • 单例模式

    单例模式及C++实现代码单例模式4种实现详解 c++11改进我们的模式之改进单例模式 单例模式(Singleton...

  • 单例模式和GCD单例实现

    1、传统单例模式2、GCD单例模式3、用宏实现GCD单例模式4、用宏实现GCD单例模式,名称随类名变化而变化 单例...

  • kotlin实现单例模式

    1.懒汉式实现单例模式 2.线程安全懒汉式实现单例模式 3.双重校验懒汉式实现单例模式 4.静态内部类方式实现单例模式

  • 单例模式

    饿汉模式: 懒汉模式: Double CheckLock(DCL)实现单例 静态内部类实现单例 枚举单例 使用容器...

  • iOS 单例

    单例模式实现不能使用继承 定义单例实现 简写 定义单例实现宏

  • 单例模式的常用实现方式

    单例模式属于最常用的设计模式,Java中有很多实现单例模式的方式,各有其优缺点 实现方式对比 单例实现方式线程安全...

网友评论

      本文标题:单例模式的实现

      本文链接:https://www.haomeiwen.com/subject/wkkjuftx.html