设计模式:单例模式

目录

  • 什么是单例模式
  • 为什么使用单例模式
  • 常见的单例写法
    • [1. 懒汉式(Lazy Initialization)](#1. 懒汉式(Lazy Initialization))
    • [2. 双重检查锁定(Double-Checked Locking)](#2. 双重检查锁定(Double-Checked Locking))
    • [3. 饿汉式(Eager Initialization)](#3. 饿汉式(Eager Initialization))
    • [4. 枚举实现单例](#4. 枚举实现单例)
  • 总结

什么是单例模式

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

为什么使用单例模式

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

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

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

常见的单例写法

1. 懒汉式(Lazy Initialization)

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

java 复制代码
public class Singleton {
       private static Singleton instance;
       private Singleton() {
           // 私有构造函数,防止外部实例化
       }
       public static synchronized Singleton getInstance() {
           if (instance == null) {
               instance = new Singleton();
           }
           return instance;
       }
   }

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

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

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

java 复制代码
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;
       }
   }

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

3. 饿汉式(Eager Initialization)

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

java 复制代码
public class Singleton {
       private static Singleton instance = new Singleton();
       private Singleton() {
           // 私有构造函数,防止外部实例化
       }
       public static Singleton getInstance() {
           return instance;
       }
   }

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

4. 枚举实现单例

java 复制代码
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. enum类的本质其实是一个final修饰的类,因为枚举的性质,INSTANCE 又是由final static 修饰的。所以我们用enum来创建单例,是由JVM来管理这个实例,保证了线程安全。
  2. 防止反序列化产生新的实例:枚举类没有构造方法,也不支持反射机制来创建新的实例,因此可以防止通过反序列化等方式产生新的对象

总结

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

相关推荐
workflower3 小时前
装备企业的 AI 路线图
人工智能·深度学习·机器学习·设计模式·机器人
geovindu13 小时前
CSharp:Chain of Responsibility Pattern
开发语言·后端·设计模式·c#·.net·责任链模式·行为模式
梓仁沐白15 小时前
【Agent 设计模式】多智能体协作
microsoft·设计模式·php
努力学习的廖同学15 小时前
前端进阶-设计模式
设计模式
workflower2 天前
情境感知系统
人工智能·机器学习·设计模式·自然语言处理·机器人
咖啡八杯2 天前
设计模式中的原则
设计模式·接口隔离原则·里氏替换原则·开闭原则·合成复用原则·单一职责原则
安冬的码畜日常2 天前
【工欲善其事】深入理解 Node.js 带并发上限的异步任务批量执行逻辑
javascript·设计模式·node.js·ai编程·异步编程·并发执行
AI大法师2 天前
一个机场如何被做成 IP 场景:宝可梦机场的设计方法总结
大数据·人工智能·设计模式·新媒体运营
晚安code2 天前
干掉成山的 if-else:工厂造、策略选,一文讲透两个模式的配合
后端·设计模式
workflower3 天前
从幻觉,到现实
人工智能·深度学习·机器学习·设计模式·机器人