美文网首页
你真的会写单例模式吗?

你真的会写单例模式吗?

作者: Coder_老王 | 来源:发表于2019-03-26 15:28 被阅读0次

本文基于Java语言实现

单实例Singleton设计模式可能是被讨论和使用的最广泛的一个设计模式了,这可能也是面试中问得最多的一个设计模式了。这个设计模式主要目的是想在整个系统中只能出现一个类的实例。

下面是一些常见的写法和存在的问题,以及如何优雅的来实现一个单例。

1.懒汉模式(线程不安全)

public class Singleton {
    private static Singleton sInstance;

    private Singleton(){};

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

该方式存在的问题是:
在多线程情况下,如果多个线程同时调用getInstance()的话,那么,可能会有多个进程同时通过 (sInstance== null)的条件检查,于是,多个实例就创建出来,并且很可能造成内存泄露问题。

为了解决多线程安全问题,我们考虑给方法加锁,于是有了下面这种形式:

2.懒汉模式(线程安全)

public class Singleton1 {
    private static Singleton1 sInstance;

    private Singleton1() {
    };

    public static synchronized Singleton1 getInstance() {
        if (sInstance == null) {
            sInstance = new Singleton1();
        }
        return sInstance;
    }
}

//或者

public class Singleton2 {
    private static Singleton2 sInstance;

    private Singleton2() {
    };

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

呐,这种形式的问题主要是效率低下,为什么呢?
因为只要是进入getInstance()的线程都得被同步,创建对象的动作只有一次,后面的动作全是读取那个成员变量,这些读取的动作是不需要线程同步的。为了一个初始化的创建动作,居然让我们搭上了所有的读操作,严重的影响了后续的性能!

3.饿汉模式

public class Singleton {
    private static Singleton sInstance = new Singleton();
    private Singleton() {
    };

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

饿汉模式在类加载的时候就对实例进行创建,实例在整个程序周期 都存在。它的好处是只在类加载的时候创建一次实例,不会存在多个线程创建多个实例的情况,避免了多线程同步的问题。它的缺点也很明显,即使这个单例没有用到也会被创建,而且在类加载之后就被创建,内存就被浪费了。

4.双重校验锁

public class Singleton {
    private volatile static Singleton sInstance;

    private Singleton() {
    };

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

这种写法应该说可以基本可以解决上面提到的这些问题,但是这个仅在Java 1.5版后有用,1.5版之前用这个变量也有问题,因为老版本的Java的内存模型是有缺陷的。当然现在也很少有用1.5之前的版本了。
不过,这种写法稍显复杂,一点都不优雅!

5.静态内部类

public class Singleton {
    private Singleton() {
    };

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

    private static class Holder {
        private static final Singleton INSTANCE = new Singleton();
    }
}

这是《Effective Java》中推荐的写法,由于 Holder 是私有的,除了 getInstance()之外没有办法访问它,因此它只有在getInstance()被调用时才会真正创建;同时读取实例的时候不会进行同步,没有性能缺陷;也不依赖 JDK 版本。

6.枚举类型

public enum Singleton {
    INSTANCE;
    public void whatererMethod() {
    }
}

这是新版的《Effective Java》推荐的写法。
通过反编译可知枚举实际上就是一个继承Enum的类。所以它的本质还是一个类,因为枚举的特点,它只会有一个实例,同时保证了线程安全、反射安全和反序列化安全。

相关文章

  • 单例模式(Java内部类加载顺序)

    你真的会写单例模式吗——Java实现Android设计模式源码解析之单例模式深度分析 Java 的枚举类型:枚举的...

  • 你真的会写单例吗?

    你真的会写单例吗? 摘录来源 单例的正确姿势 Java单例模式可能是最简单也是最常用的设计模式,一个完美的单例需要...

  • 单例模式的优化方案

    参考:你真的会写单例吗? 单例模式最常见的就是懒汉式加载: 例: 当调用getInstance方法时才去创建对象,...

  • Java单例模式

    转载: 你真的会写单例模式吗-------Java实现 单例模式可能是代码最少的模式了,但是少不一定意味着简单,想...

  • 你真的会写单例模式吗?

    单例模式可能是代码最少的模式了,但是少不一定意味着简单,想要用好、用对单例模式,还真得费一番脑筋。本文对Java中...

  • 你真的会写单例模式吗?

    本文基于Java语言实现 单实例Singleton设计模式可能是被讨论和使用的最广泛的一个设计模式了,这可能也是面...

  • 你真的会写单例模式吗

    作者:DeppWang、原文地址 人生在世,谁不面试。单例模式:一个搞懂不加分,不搞懂减分的知识点 又一篇一抓一大...

  • 你真的会写单例模式吗

    作者:DeppWang、原文地址 人生在世,谁不面试。单例模式:一个搞懂不加分,不搞懂减分的知识点 又一篇一抓一大...

  • 你真的会写单例模式吗——Java实现

    单例模式可能是代码最少的模式了,但是少不一定意味着简单,想要用好、用对单例模式,还真得费一番脑筋。本文对Java中...

  • 单例模式是什么?你真的会写JAVA的单例模式吗?

    欢迎关注微信公众号:乱敲代码后台回复关键字Java领取学习资料 单例模式可能是代码最少的模式了,但是少不一定意味着...

网友评论

      本文标题:你真的会写单例模式吗?

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