设计模式之 - 单例模式

2021/08/06 design-pattern 共 1590 字,约 5 分钟
Bob.Zhu

单例模式是软件开发过程中经常用到的一种设计模式,但如果优雅的实现单例模式,并不是一个简单的问题。

常规加锁模式

单例模式需要注意的问题,就是多个线程同时请求的时候,只允许一个线程进行单例的创建和初始化,那么 显然可以想到使用 synchronize 关键字进行约束。但是synchronize关键字并不能保证方法内的 指令不被重排序,比如创建对象的时候有三个步骤:

  1. 创建对象
  2. 初始化对象
  3. 返回对象

正常情况下的指令执行顺序是 1 2 3,如果发生了指令重排,那么可能的结果是 1 3 2,也就是在 未初始化的情况下就返回了对象,所以还需要增加 volatile 关键字约束单例变量,以保证不会 发生指令重排。

public class SingletonDoubleCheck {
  /** 保存该类的唯一-实例,使用volatile关键字修饰instance */
  private static volatile SingletonDoubleCheck instance;

  /** 私有构造器使其他类无法直接通过new创建该类的实例 */
  private SingletonDoubleCheck() {
    //什么也不做
  }

  public static SingletonDoubleCheck getInstance() {
    if (null == instance) {// 操作①:第1次检查
      synchronized (SingletonDoubleCheck.class) {
        if (null == instance) {// 操作②:第2次检查
          instance = new SingletonDoubleCheck();//操作③
        }
      }
    }
    return instance;
  }
}

静态内部类的单例模式

类的静态变量被初次访问会触发Java虚拟机对该类进行初始化,即该类的静态变量的值会变为其初始值 而不是默认值。因此,静态方法getInstance()被调用的时候Java虚拟机会初始化这个方法所访问的 内部静态类InstanceHolder。这使得InstanceHolder的静态变量INSTANCE被初始化,从而使 StaticHolderSingleton类的唯一实例得以创建。由于类的静态变量只会创建一次,因此 StaticHolderSingleton (单例类)只会被创建一次。

public class SingletonStaticHolder {

  /** 私有构造器 */
  private SingletonStaticHolder() {
  }

  private static class InstanceHolder {
    /** 保存外部类的唯一实例 */
    final static SingletonStaticHolder INSTANCE = new SingletonStaticHolder();
  }

  public static SingletonStaticHolder getInstance() {
    return InstanceHolder.INSTANCE;
  }

}

枚举实现单例模式

public class SingletonEnumBase {
  public static void main(String[] args) {
    Singleton.INSTANCE.doSomething();
  }

  public enum Singleton {
    INSTANCE;

    Singleton() {
    }

    public void doSomething() {
    }
  }

}

这里,枚举类型Singleton 相当于-一个单例类,其字段INSTANCE值相当于该类的唯一实例。这个实例 是在Singleton.INSTANCE 初次被引用的时候才被初始化的。仅访问Singleton本身(比如上述的 Singleton.class. getName()调用)并不会导致Singleton的唯一实例被初始化。

参考资料

文档信息

Search

    Table of Contents