「手写设计模式」单例模式

253 阅读2分钟

理解名词

单例设计模式(Singleton Design Pattern)是一种创建型设计模式。

单例:一个类只允许创建一个对象(或者实例),那这个类就是一个单例类;

作用

  1. 从业务概念上,有些数据在系统中只应该保存一份,就比较适合设计为单例类。比如,系统的配置信息类。
  2. 使用单例解决资源访问冲突问题

关键实现步骤

  • 饿汉式
  1. 私有化构造方法
  2. 定义instance 静态实例并在类加载期间就进行初始化
  3. 定义静态方法getInstance

饿汉式的实现方式,在类加载的期间,就已经将 instance 静态实例初始化好了,所以,instance 实例的创建是线程安全的。不过,这样的实现方式不支持延迟加载实例。

  • 双重检测懒汉式
  1. 私有化构造方法
  2. 定义一个volatile static类型的实例变量instance
  3. 定义静态方法getInstance,先判断instance是否为null,是就对单例类进行synchronized加锁,接着再判断判断instance是否为null,是则进行初始化操作。

双重检测实现方式既支持延迟加载、又支持高并发的单例实现方式。只要 instance 被创建之后,再调用 getInstance() 函数都不会进入到加锁逻辑中。所以,这种实现方式解决了懒汉式并发度低的问题。

  • 静态内部类
  1. 私有化构造方法
  2. 定义一个内部静态私有类SingletonHolder,在SingletonHolder内部定义一个私有静态final类型的外部类变量instance,并初始化
  3. 在外部类定义静态方法getInstance,返回SingletonHolder.instance

利用 Java 的静态内部类来实现单例。这种实现方式,既支持延迟加载,也支持高并发,实现起来也比双重检测简单。

  • 枚举
  1. 定义一个枚举类
  2. 定义一种枚举叫做INSTANCE
  3. 定义其余变量和方法
  4. 使用时直接调用INSTANCE.XXX方法

最简单的实现方式,基于枚举类型的单例实现。这种实现方式通过 Java 枚举类型本身的特性,保证了实例创建的线程安全性和实例的唯一性。

代码示例

饿汉式


public class IdGenerator { 
  private AtomicLong id = new AtomicLong(0);
  private static final IdGenerator instance = new IdGenerator();
  private IdGenerator() {}
  public static IdGenerator getInstance() {
    return instance;
  }
  public long getId() { 
    return id.incrementAndGet();
  }
}

双重检测懒汉式


public class IdGenerator { 
  private AtomicLong id = new AtomicLong(0);
  private static volatile IdGenerator instance;
  private IdGenerator() {}
  public static IdGenerator getInstance() {
    if (instance == null) {
      synchronized(IdGenerator.class) { // 此处为类级别的锁
        if (instance == null) {
          instance = new IdGenerator();
        }
      }
    }
    return instance;
  }
  public long getId() { 
    return id.incrementAndGet();
  }
}

静态内部类


public class IdGenerator { 
  private AtomicLong id = new AtomicLong(0);
  private IdGenerator() {}

  private static class SingletonHolder{
    private static final IdGenerator instance = new IdGenerator();
  }
  
  public static IdGenerator getInstance() {
    return SingletonHolder.instance;
  }
 
  public long getId() { 
    return id.incrementAndGet();
  }
}

枚举

public enum IdGenerator {
  INSTANCE;
  private AtomicLong id = new AtomicLong(0);
 
  public long getId() { 
    return id.incrementAndGet();
  }
}

业界经典应用

  • Spring Bean管理