设计模式-单例模式

作者: MonkeyLqj | 来源:发表于2019-08-08 11:05 被阅读8次

1 单例模式介绍

单例模式是应用最广的模式之一,在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个全局对象,这样有利于我们协调系统整体的行为。例如,创建一个对象需要消耗过多资源,如要访问IO、数据库等资源时就需要考虑使用单例模式

2 单例模式定义

确保一个类只有一个实例,并且提供一个全局访问点。

3 单例模式的使用场景

在一个系统中,要求一个类有且仅有一个对象,具体使用场景:

  • 整个项目需要一个共享访问点或共享数据。
  • 创建一个对象需要消耗的资源过多,比如访问I/O、数据库等资源。
  • 工具类对象。

4 单例模式使用示例

单例模式有多种写法,我们分别看下:

4.1 饿汉模式

public class Singleton {
    private static Singleton mInstance = new Singleton();
    //构造函数
    private Singleton(){
    }
    //共有静态函数,对外暴露获取单例对象的接口
    public static Singleton getInstance(){
        return mInstance;
    }
}

这种方式在类加载时就完成了初始化,所以类加载较慢,但是获取对象的速度快。这种方式基于类加载机制,避免了多线程的同步问题。如果从来没有使用过这个实例,则会造成内存的浪费。

4.2 懒汉模式

懒汉模式声明一个静态对象,在用户第一次调用时初始化。而上述的饿汉模式是在声明静态对象的时候初始化的。 懒汉模式的的两种实现方式如下:

4.2.1(线程不安全)
public class Singleton {
    private static Singleton mInstance;
    private Singleton() {
    }
    public static Singleton getInstance() {
        if (null == mInstance){
            mInstance = new Singleton();
        }
        return mInstance;
    }
}

这种懒汉模式虽然节约了资源,到那时第一次加载时需要实例化,反应稍慢些。但是在多线程的时候不能保证唯一性。

4.2.2(线程安全)
public class Singleton {
    private static Singleton mInstance;
    private Singleton() {
    }
    public static synchronized Singleton getInstance() {
        if (null == mInstance){
            mInstance = new Singleton();
        }
        return mInstance;
    }
}

我们可以发现在getInstance方法中添加了synchronized关键字,即getInstance方法是一个同步方法,可以在多线程情况下保证单例对象的唯一性。而每次调用getInstance方法都会进行同步造成不必要的同步开销,而我们大部分时候是用不到同步的。所以这种模式一般不建议使用。

4.3 双重检查模式(DCL)

Double Check Lock(DCL) 方式实现单例模式的优点是既能够在需要时才实例化,又能够保证线程的安全,且单例对象初始化后调用getInstance不进行同步锁。如下示例:

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

我们可以看到getInstance方法中对mInstance进行了两次判空,第一次判断主要是为了避免不必要的同步,第二层的判断是为了在null的情况下创建实例。因为在某些情况下会出现失效问题即DCL失效问题,可以使用volatile关键字处理这个问题。使用volatile或多或少的会影响到性能,但是考虑到程序的正确性,牺牲这点性能还是值得的。

DCL的优点:资源利用效率高,第一次执行getInstance时店里对象才被实例化,效率高。
DCL的缺点:第一次加载时反应稍慢,在高并发环境下也有一定的缺陷。

4.4 静态内部类的单例模式

public class Singleton {
    private Singleton() {
    }
    public static Singleton getInstance() {
        return SingletonHoler.sInstance;
    }
    private static class SingletonHoler{
        private static final Singleton sInstance = new Singleton();
    }
}

Java静态内部类的特性是,加载的时候不会加载内部静态类,使用的时候才会进行加载。
第一次加载Singleton类时并不会初始化sInstance,只有第一次调用getInstance方法时虚拟机加载SingletonHolder并初始化sInstance。这样不仅能确保线程安全,也能保证Singleton类的唯一性。所以,推荐使用静态内部类单例模式。

4.5 枚举单例模式

public enum Singleton {
    INSTANCE;
}

外部调用由原来的Singleton.getInstance变成了Singleton.INSTANCE了。

默认枚举实例的创建是线程安全的,并且在任何情况下都是单例。枚举单例的有点就是简单,缺点是可读性不高。

5 总结

单例模式是运用频率很高的模式,在我们客户端通常是没有高并发的情况,所以选择哪种方式并不会有太大的影响。出于效率考虑,推荐使用静态内部类的单例模式和DCL的单例模式。

优点:

  • 由于单例模式在内存中只有一个实例,减少内存开支,特别是一个对象需要频繁创建、销毁时,而且创建或销毁时性能又无法优化,单例模式的优势就十分明显。
  • 由于单例模式只生成一个实例,所以减少了系统的性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可通过在应用启动时直接产生一个单例对象,然后用永久驻留的方式解决。
  • 单例模式可以避免对资源的多重占用,如一个文件的操作,由于只有一个实例存在内存中,避免对同一个资源文件的同时操作。
  • 单例模式可以在系统设置全局的访问点,优化和共享资源访问。例如,可以设计一个单例类,负责所有数据表的映射处理。

缺点:

  • 单例模式一般没有接口,扩展很困难,除非修改代码。
  • 单例对象如果持有Context,那么很容易引发内存泄露,此时需要注意传递给单例对象的Context最好是Application Context

相关文章

  • 单例模式Java篇

    单例设计模式- 饿汉式 单例设计模式 - 懒汉式 单例设计模式 - 懒汉式 - 多线程并发 单例设计模式 - 懒汉...

  • python中OOP的单例

    目录 单例设计模式 __new__ 方法 Python 中的单例 01. 单例设计模式 设计模式设计模式 是 前人...

  • 单例

    目标 单例设计模式 __new__ 方法 Python 中的单例 01. 单例设计模式 设计模式设计模式 是 前人...

  • 设计模式 - 单例模式

    设计模式 - 单例模式 什么是单例模式 单例模式属于创建型模式,是设计模式中比较简单的模式。在单例模式中,单一的类...

  • 设计模式

    常用的设计模式有,单例设计模式、观察者设计模式、工厂设计模式、装饰设计模式、代理设计模式,模板设计模式等等。 单例...

  • 2018-04-08php实战设计模式

    一、单例模式 单例模式是最经典的设计模式之一,到底什么是单例?单例模式适用场景是什么?单例模式如何设计?php中单...

  • python 单例

    仅用学习参考 目标 单例设计模式 __new__ 方法 Python 中的单例 01. 单例设计模式 设计模式设计...

  • 基础设计模式:单例模式+工厂模式+注册树模式

    基础设计模式:单例模式+工厂模式+注册树模式 单例模式: 通过提供自身共享实例的访问,单例设计模式用于限制特定对象...

  • 单例模式

    JAVA设计模式之单例模式 十种常用的设计模式 概念: java中单例模式是一种常见的设计模式,单例模式的写法...

  • 设计模式之单例模式

    单例设计模式全解析 在学习设计模式时,单例设计模式应该是学习的第一个设计模式,单例设计模式也是“公认”最简单的设计...

网友评论

    本文标题:设计模式-单例模式

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