设计模式——单例

设计模式——单例

  • 是什么

    • 单例是创建型设计模式
    • 在内存中只有一个实例化对象
    • 全局只有一个访问点获取实例化对象
  • 解决什么问题

    • 对象重复创建,浪费开销
    • 内存有多个相同的对象,浪费空间
  • 实现方式分类

    • 饿汉模式,类初始化完创建对象
    • 懒汉模式,第一次调用时创建对象
  • 饿汉模式实现方式

    • 私有化构造方法

    • 初始化私有的static final属性为实例化对象

    • 对外暴露getInstance静态方法

    • 代码示例

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      class Singleton {
      private static final Singleton INSTANCE = new Singleton();

      private Singleton() {
      }

      public static Singleton getInstance() {
      return INSTANCE;
      }
      }
  • 懒汉模式实现方式

    • getInstance方法加synchronized,防止多线程同时调用创建多个对象。所有获取单例实例化对象都会加锁。单例、线程安全、性能差。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      class Singleton {
      private static Singleton INSTANCE = null;

      private Singleton() {
      }

      public static synchronized Singleton getInstance() {
      if (INSTANCE == null) {
      INSTANCE = new Singleton();
      }
      return INSTANCE;
      }
      }
    • 双重检查锁,只有在INSTANCE为空的时候加锁,常规获取单例不加锁,避免频繁加锁;给INSTANCE添加volatile,多线程其他线程可以获取INSTANCE最新创建情况。单例、线程安全、性能好。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      class Singleton {
      private volatile static Singleton INSTANCE = null;

      private Singleton() {
      }

      public static Singleton getInstance() {
      if (INSTANCE == null) {
      synchronized (Singleton.class) {
      if (INSTANCE == null) {
      INSTANCE = new Singleton();
      }
      }
      }
      return INSTANCE;
      }
      }
    • 静态内部类,利用类加载机制保障单例及线程安全。单例、线程安全、性能好。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      class Singleton {
      private static class SingletonHolder {
      private static final Singleton INSTANCE = new Singleton();
      }

      private Singleton() {
      }

      public static final Singleton getInstance() {
      return SingletonHolder.INSTANCE;
      }
      }
    • 枚举,枚举类型及枚举变量在JVM中都是唯一的,同时枚举类型在序列化和反序列化在JVM也是同一个,可以保证绝对单例。序列化单例、线程安全、性能好。

      1
      2
      3
      public enum Singleton {
      INSTANCE;
      }
  • 关联知识点

    • 类加载过程,加载->验证->准备->解析->初始化,初始化会对静态变量赋值,由此可知饿汉模式类加载完成对象即创建完。

      • 加载:字节码加载到内存
      • 验证:验证格式
      • 准备:静态变量分配内存,初始化默认值
      • 解析:静态链接,符号引用转换为直接引用
      • 初始化:静态变量赋值,静态方法区执行
    • 静态内部类,静态内部类在使用的时候才会加载,类加载会初始化static变量。

    • 线程安全,内存模型,volatile,synchronized,设计知识点略多,以后单独写。

    • 枚举特性,枚举类型及枚举变量在JVM中都是唯一的。在序列化的时候Java将枚举对象的name属性输出到结果中,反序列化的时候通过java.lang.Enum的valueOf方法来根据名字查找枚举对象。