单例模式总结

06-02 1231阅读

单例模式本身是一种设计模式,是否线程安全取决于具体实现方式。以下是不同单例实现方式的线程安全性分析及优化方案:


一、线程不安全的单例实现

1. 懒汉式(未同步)
public class Singleton {
    private static Singleton instance;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {                // 线程A和B可能同时进入此判断
            instance = new Singleton();        // 导致创建多个实例
        }
        return instance;
    }
}

问题:多线程同时调用 getInstance() 会破坏单例性。


二、线程安全的单例实现

1. 饿汉式(线程安全)
public class Singleton {
    private static final Singleton instance = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() {
        return instance;  // 类加载时已初始化,JVM保证线程安全
    }
}

特点:

  • 优点:实现简单,无锁性能高
  • 缺点:无法延迟加载(即使未使用也会初始化)
    2. 懒汉式(同步方法)
    public class Singleton {
        private static Singleton instance;
        private Singleton() {}
        public static synchronized Singleton getInstance() {  // 方法级同步
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }
    

    特点:

    • 优点:实现简单,保证线程安全
    • 缺点:每次调用都加锁,性能差(锁粒度太大)
      3. 双重检查锁定(DCL,线程安全)
      public class Singleton {
          private static volatile Singleton instance;  // 必须用volatile
          private Singleton() {}
          public static Singleton getInstance() {
              if (instance == null) {                  // 第一次检查(无锁)
                  synchronized (Singleton.class) {     // 加锁
                      if (instance == null) {          // 第二次检查(有锁)
                          instance = new Singleton();  // volatile禁止指令重排序
                      }
                  }
              }
              return instance;
          }
      }
      

      关键点:

      • volatile 防止指令重排序(避免返回未初始化的对象)
      • 减少锁竞争(仅首次创建时同步)
        4. 静态内部类(线程安全)
        public class Singleton {
            private Singleton() {}
            private static class Holder {
                static final Singleton INSTANCE = new Singleton();  // 类加载时初始化
            }
            public static Singleton getInstance() {
                return Holder.INSTANCE;  // 首次调用时加载Holder类
            }
        }
        

        特点:

        • 结合懒加载与无锁线程安全
        • JVM保证类加载过程的线程安全性
          5. 枚举实现(最佳实践)
          public enum Singleton {
              INSTANCE;  // 枚举实例天然单例且线程安全
              public void doSomething() {
                  // 业务方法
              }
          }
          

          优势:

          • 绝对防止反射攻击(枚举类无法通过反射创建实例)
          • 自动处理序列化与反序列化
          • 代码最简洁

            三、线程安全单例的核心要点

            实现方式线程安全延迟加载性能防反射防序列化
            饿汉式⭐⭐⭐⭐
            同步懒汉式
            双重检查锁定⭐⭐⭐
            静态内部类⭐⭐⭐⭐
            枚举⭐⭐⭐⭐

            四、常见面试陷阱

            1. 为什么DCL需要volatile?

              • 防止指令重排序:new Singleton() 的字节码分为三步(分配内存→初始化→引用赋值),不加volatile可能导致其他线程获取到未初始化的对象。
              • 静态内部类如何保证线程安全?

                • JVM在类加载时(首次访问Holder.INSTANCE)会加锁(ClassLoader机制),保证初始化过程线程安全。
                • 枚举单例为何能防反射?

                  • 枚举类的构造方法在反射调用时会抛出IllegalArgumentException,源码中明确禁止反射创建枚举实例。

            五、总结回答

            “单例模式能否保证线程安全取决于具体实现方式:

            1. 线程不安全实现:如无同步的懒汉式
            2. 线程安全实现:
              • 饿汉式(简单但无法延迟加载)
              • 双重检查锁定(需加volatile)
              • 静态内部类(兼顾性能与懒加载)
              • 枚举(最佳实践,防反射/序列化攻击)

                实际开发中推荐使用枚举或静态内部类实现单例模式。”

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码