• 设计模式:单例模式


    什么是单例模式

    单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供全局访问点来获取该实例。单例模式的目的是限制一个类只能创建一个对象,以便在整个应用程序中共享该对象的状态和行为。

    为什么使用单例模式

    在单例模式中,类会提供一个静态方法或静态变量来获取单例实例。这个静态方法会检查是否已经存在实例,如果存在则返回该实例,如果不存在则创建一个新的实例。同时,为了防止通过其他方式创建实例,单例模式的构造函数通常会被设置为私有的,这样外部无法直接实例化该类。

    单例模式广泛应用于需要共享资源、控制资源访问以及避免重复创建对象等场景。例如,数据库连接池、日志记录器、配置文件管理器等都可以使用单例模式来实现。

    通过单例模式,我们可以确保在整个应用程序中使用相同的实例,避免了资源的浪费和不一致性的问题。

    常见的单例写法

    1. 懒汉式(Lazy Initialization)

    这种写法在第一次使用时才创建实例。示例代码如下:

    public class Singleton {
           private static Singleton instance;
           private Singleton() {
               // 私有构造函数,防止外部实例化
           }
           public static synchronized Singleton getInstance() {
               if (instance == null) {
                   instance = new Singleton();
               }
               return instance;
           }
       }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这种写法简单直观,但在多线程环境下可能存在线程安全问题,需要使用 synchronized 关键字来解决。

    2. 双重检查锁定(Double-Checked Locking)

    这种写法在懒汉式的基础上进行了优化,减少了加锁的开销。示例代码如下:

    public class Singleton {
           private volatile static Singleton instance;
           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
    • 13
    • 14
    • 15
    • 16

    使用 volatile 关键字和双重检查的方式,可以在多线程环境下保证线程安全。

    3. 饿汉式(Eager Initialization)

    这种写法在类加载时就创建实例,不存在线程安全问题。示例代码如下:

    public class Singleton {
           private static Singleton instance = new Singleton();
           private Singleton() {
               // 私有构造函数,防止外部实例化
           }
           public static Singleton getInstance() {
               return instance;
           }
       }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这种写法简单直接,但可能会造成资源浪费,因为实例在类加载时就被创建,即使后续并没有被使用到。

    4. 枚举实现单例

    public class SingletonObj {
        //内部类使用枚举
        private enum SingletonEnum {
            INSTANCE;
    
            private SingletonObj singletonObj;
    
            //在枚举类的构造器里初始化singletonObj
            SingletonEnum() {
                singletonObj = new SingletonObj();
            }
    
            private SingletonObj getSingletonObj() {
                return singletonObj;
            }
        }
    
        //对外部提供的获取单例的方法
        public static SingletonObj getInstance() {
            //获取单例对象,返回
            return SingletonEnum.INSTANCE.getSingletonObj();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    1. enum类的本质其实是一个final修饰的类,因为枚举的性质,INSTANCE 又是由final static 修饰的。所以我们用enum来创建单例,是由JVM来管理这个实例,保证了线程安全。
    2. 防止反序列化产生新的实例:枚举类没有构造方法,也不支持反射机制来创建新的实例,因此可以防止通过反序列化等方式产生新的对象

    总结

    单例模式比较简单,我们只要确保一个类只有一个实例,并提供全局访问点来获取该实例就行了。在spring源码中是放到一个唯一的且并发安全的Map中,每次使用都是从这个唯一的map中获取对象。

  • 相关阅读:
    mini-Imagenet处理
    7-143 降价提醒机器人
    东软睿驰受邀出席恩智浦汽车生态技术峰会,见证S32 CoreRide开放平台全新发布
    如何快速找到华为手机中下载的文档
    下划线命名转驼峰
    C语言的冒泡排序
    46-3 护网溯源 - 溯源报告编写
    在Linux中安装宝塔面板
    winform 获取指定的form
    三十四、openlayers官网示例Dynamic clusters解析——动态的聚合图层
  • 原文地址:https://blog.csdn.net/qq_27586963/article/details/132840551