单例模式(Singleton Pattern)

引入

对于一个系统中的某些类来说, 只有一个实例很重要. 例如一个系统中可以有多个打印任务,但是只能有一个正在工作中的打印任务。只能有一个窗口管理器或文件系统, 只能有一个ID生成器。此时让这个类自身负责保存它的唯一实例, 并且无法在外部被实例化比较好。并且提供一个方便的访问该实例的方法

定义

单例模式,确保某一个类只有一个实例。而且自行实例化,并向整个系统提供这个实例

代码分析

结构太简单, 咱们直接看代码

/**
 * 带有双重判断的单例模式
 *
 * @version 0.1
 * @author xy
 * @date 2018年1月25日 下午4:48:41
 */
public class SyncSingleton {

  //一个静态的实例
  // 为什么要用 volatile, 禁止指令重排序: https://www.zhihu.com/question/56606703
    private volatile static SyncSingleton instance;

  //私有化构造函数
    private SyncSingleton() {}
  //给出一个公共的静态方法返回一个单一实例
    public static SyncSingleton getInstance() {
        if (instance == null) {
          //这里第二重判断:AB两个线程同时进入第一个判断内部,此
          //时A当先拿到锁进入第二判断,创建了对象,B拿到锁后会再次
          //进行判断,如果此处不判断,则会创建第二个对象;
            synchronized (SyncSingleton.class) {
                if (instance == null) {
                    instance = new SyncSingleton();
                }
            }
        }
        return instance;
    }
}

///////////////////////// 推荐这种写法: 借助 jvm 的特性帮助实现 singleton ////////////////////////////////////

/**
 * 更安全, 更简单的单例
 *
 *首先来说一下,这种方式为何会避免了上面莫名的错误,
 *主要是因为一个类的静态属性只会在第一次加载类时初始化,这是类加载机制决定的
 *另外由于静态变量只初始化一次,所以singleton仍然是单例的。
 *
 * @version 0.1
 * @author xy
 * @date 2018年1月25日 下午5:02:23
 */
public class Singleton {
    private Singleton(){}
    public static Singleton getInstance(){
        return SingletonInstance.instance;
    }
    //类的静态成员只加载一次,这保证了只有一个对象
    private static class SingletonInstance{
        private static Singleton instance = new Singleton();
    }
}

模式分析

  • 构造函数私有
  • 提供一个公有静态工厂方法
  • 双重判断, 同步第二个判断, 解决多线程问题
  • 原型模式:单例模式是只有一个实例,原型模式每拷贝一次都会创造一个新的实例。

优点:

  • 节约系统资源
  • 在单例模式基础上拓展, 获取指定个数的实例

缺点:

  • 违背了单一职责原则, 单例类既有工厂方法, 又有业务方法, 即充当工厂, 又充当产品

适用场景

  • 系统只需要一个实例对象
  • 客户端调用只允许一个调用点
  • 系统要求一个类只能有指定个数的实例, 可拓展单例模式

应用实例

主键编号生成器

spring中的bean默认都是单例生成的;

results matching ""

    No results matching ""