单例模式


单例模式:

  • 私有构造函数+提供一个方法或者变量让外部可以获取实例

  1. 饿汉式实现

    • 枚举

    • 静态成员变量实例初始化

    • 提供方法返回成员变量(实例化的类)

  2. 懒汉(需要时加载)

    • 在方法中直接返回

    • 在方法中返回子类的静态成员变量(实例化好的class)

    • synchronized(class) 双重检测, 判断是否有实例了 + 获取类锁

注意:

  • 枚举类型的单例,因为反序列化会检测是不是enum,是就会抛异常,所以不用担心反序列化问题且天然单例。

  • 双重检测可能有空指针问题,因为指令重排序,可能返回一个不完整的对象,所以可以用 volatile 修饰变量。

  • 推荐内部类实现的懒汉模式。

  • 静态变量只会加载一次,但是是否完整就是不一定了。可能在没初始化完,就已经给变量赋予地址了。

代码案例

  1. 枚举单例 特点: 天然线程安全,防反射、防反序列化破坏单例,实现简单

  1. 饿汉式单例(静态成员变量实例初始化) 特点:类加载时就创建实例,线程安全(类加载天然同步),可能造成“类加载即创建”,有些场景会浪费资源

  1. 懒汉式(非线程安全,最简单版,不推荐) 特点:按需加载(第一次用到时才创建),多线程环境会有并发问题(可能创建多个实例)

  1. 懒汉式 + synchronized 整个方法(简单但性能一般) 特点:在方法上加 synchronized,保证线程安全,实现简单,每次调用都要获取锁,性能一般

  1. 懒汉式 - 双重检查锁(DCL,需 volatile) 特点(对应你笔记里的“synchronized(class) 双重检测 + volatile”): 兼顾“按需加载 + 多线程性能”,实现稍复杂,但非常常见,instance 必须用 volatile 修饰,以防指令重排序返回“半初始化对象”

  1. 静态内部类实现懒汉模式 特点:

    • 利用类加载机制实现“按需加载 + 线程安全”

    • 外部类加载时不会立即创建实例,只有第一次调用 getInstance() 时,才加载内部类并创建实例

    • 性能好,写法优雅,是懒汉模式中非常推荐的一种

总结

  • 推荐优先使用:枚举单例、静态内部类单例

  • 想兼顾懒加载和性能:静态内部类 > DCL

  • 只在单线程或测试/demo 用:最简单的懒汉式(不加锁)

Last updated