0

单例模式

2024.10.11 | cuithink | 701次围观

4. 单例模式

单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供了一种全局访问点以访问该实例

饿汉式和懒汉式的区别

  1. 初始化时机不同:饿汉式单例模式在类加载时就立即初始化并创建单例对象,而懒汉式单例模式则是在第一次使用时才会进行初始化,并创建单例对象。

  2. 线程安全性不同:饿汉式单例模式在类加载时就创建了单例对象,因此天生就是线程安全的。而懒汉式单例模式在第一次使用时才会创建单例对象,如果多个线程同时调用getInstance()方法,可能会创建出多个单例对象,因此需要进行同步控制来保证线程安全。

  3. 内存占用不同:饿汉式单例模式在类加载时就创建了单例对象,因此占用的内存较多。而懒汉式单例模式在第一次使用时才会创建单例对象,因此占用的内存相对较少。

实现方式

  • 饿汉式

class Singleton {

    // 1. 加载该类时,单例就会自动被创建
    private static  Singleton ourInstance  = new  Singleton();

    // 2. 构造函数 设置为 私有权限
    // 原因:禁止他人创建实例 
    private Singleton() {
    }

    // 3. 通过调用静态方法获得创建的单例
    public static  Singleton newInstance() {
        return ourInstance;
    }
}
  • 懒汉式

class Singleton {
    private static  Singleton ourInstance  = null;

    private Singleton() {
    }
    
    public static  Singleton newInstance() {
     // 加入双重校验锁
    // 校验锁1:第1个if
    if( ourInstance == null){  // ①
     synchronized (Singleton.class){ // ②
      // 校验锁2:第2个 if
      if( ourInstance == null){
          ourInstance = new Singleton();
          }
      }
  }
        return ourInstance;
   }
}

// 说明
// 校验锁1:第1个if
// 作用:若单例已创建,则直接返回已创建的单例,无需再执行加锁操作
// 即直接跳到执行 return ourInstance

// 校验锁2:第2个 if 
// 作用:防止多次创建单例问题
// 原理
  // 1. 线程A调用newInstance(),当运行到②位置时,此时线程B也调用了newInstance()
  // 2. 因线程A并没有执行instance = new Singleton();,此时instance仍为空,因此线程B能突破第1层 if 判断,运行到①位置等待synchronized中的A线程执行完毕
  // 3. 当线程A释放同步锁时,单例已创建,即instance已非空
  // 4. 此时线程B 从①开始执行到位置②。此时第2层 if 判断 = 为空(单例已创建),因此也不会创建多余的实例

  • 静态内部类

原理 根据 静态内部类 的特性(外部类的加载不影响内部类),同时解决了按

需加载、线程安全的问题,同时实现简洁

1. 在静态内部类里创建单例,在装载该内部类时才会去实例化单例

2. 线程安全:类是由 JVM 加载,而 JVM 只会加载1遍,保证只有1个单例

  • 枚举

因为枚举类型是线程安全的,并且只会装载一次,设计者充分的利用了枚

举的这个特性来实现单例模式,枚举的写法非常简单,而且枚举类型是所

用单例实现中唯一一种不会被破坏的单例实现模式。

为什么枚举类可以阻止反射的破坏?

首先枚举类中是没有空参构造方法的,只有一个带两个参数的构造方法         真正原因是: 反射方法中不予许使用反射创建枚举对象


粤ICP备16076548号
发表评论