单例模式及其思想

news2025/1/13 2:43:58

本文包括以下几点↓

在这里插入图片描述

结论设计模式不是简单地将一个固定的代码框架套用到项目中,而是一种严谨的编程思想,旨在提供解决特定问题的经验和指导。

单例模式(Singleton Pattern)

意图

旨在确保类只有一个实例,并提供一个全局访问点以访问该实例。

适用性

当你希望系统中只有一个实例,并且需要从全局任何地方都能访问该实例时。

当你需要严格控制某个类的实例化过程,以确保所有代码都使用相同的实例时。

简述

单例模式的核心思想是控制对象只实例化一次,并提供一个全局访问点来获取该实例。这样可以确保在系统中只有一个实例,并且所有对该实例的访问都通过同一个访问点。

实现单例模式有几种方式,通过以下案例展开。

简单案例

六种常见的单例模式实现方式,逐一分析它们的特点和适用场景:

  1. 懒汉式之线程不安全:

源码

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  

    public static Singleton getInstance() {  
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
    }  
}

特点: 懒加载,在首次使用时创建实例化对象。在多线程环境下,可能会出现并发问题,导致创建多个实例。

适用场景: 单线程环境下的简单应用,对性能要求不高,且不会频繁使用单例的场景。

  1. 懒汉式之线程安全

源码

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
    public static synchronized Singleton getInstance() {  
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
    }  
}

特点: 同样是懒加载,但使用了 synchronized 关键字来保证线程安全。然而,这会造成性能下降,因为每次获取实例对象都需要加锁。

适用场景: 在多线程环境下使用,对性能要求不高的场景,或者对并发要求不是特别高的情况。

  1. 饿汉式

源码

public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
        return instance;  
    }  
}

特点: 在类加载时就创建实例化对象,因此不存在多线程安全问题,且访问时效率高。但可能会浪费内存,因为实例在程序启动时就创建了,即使未被使用也会占用内存。

适用场景: 对内存占用没有过多要求,且希望在程序启动时就初始化单例的场景。

  1. 双检锁/双重校验锁

源码

public class Singleton {  
    private volatile static Singleton singleton;
    private Singleton (){}
    public static Singleton getSingleton() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

特点: 通过双重检查加锁,既实现了懒加载,又保证了线程安全,且在实例已创建的情况下避免了不必要的锁竞争,因此性能较高。

适用场景: 对性能要求较高,且需要懒加载的场景,特别是在多线程环境下。

  1. 登记式/静态内部类

源码

public class Singleton {
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    private Singleton (){}
    public static final Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

特点: 通过静态内部类实现了懒加载,且保证了线程安全。在类加载时并不会初始化,只有在首次调用 getInstance() 方法时才会初始化。

适用场景: 对内存占用有要求,且希望在首次使用时才初始化的场景。

  1. 枚举类

源码

public enum Singleton {
    INSTANCE;
//  private Singleton(){}
    public Singleton getSelf() {
        return INSTANCE;
    }
}
public static void main(String[] args) {
    Singleton instance = Singleton.INSTANCE;
}

特点: 使用枚举类型实现单例,利用枚举的特性保证了在任何情况下都只会有一个实例存在。枚举类的实例在类加载时就会被初始化。

适用场景: 对内存占用没有过多要求,且希望简洁明了地实现单例的场景。枚举类也是线程安全的。

枚举类本身就是单例模式Singleton instance = Singleton.INSTANCE; 并且可以有多个枚举INSTANCE,TWO;枚举类中的INSTANCE就是Singleton对象实例,看getSelf方法不报错就知道了;枚举类的构造方法本身就是private,放开实例中的注释结果一样;枚举中的方法只能通过Singleton.INSTANCE.getSelf()的方式来调用,这就是单例的表现。

这是实现单例模式的最佳方法,它更简洁,自动支持序列化机制,绝对防止多次实例化。但不能通过反射来调用私有构造方法。

在Spring框架中的应用??

在Spring框架中,使用到单例模式思想的地方非常多,被广泛应用于管理和创建bean实例。Spring容器默认情况下会将所有的bean都配置为单例,这意味着在整个应用程序中,每个bean都只有一个实例存在。这种默认的单例模式确保了Spring应用程序的性能和资源利用率。

在Spring上下文中,通过使用@Bean@Component@Service@Repository 等注解或在配置文件中显式声明bean,Spring会自动将其配置为单例模式,即在整个应用程序中只创建一个实例。比如配置类的创建。

例如:数据库连接配置类

@Configuration
public class AppConfig {

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/mydatabase");
        dataSource.setUsername("username");
        dataSource.setPassword("password");
        return dataSource;
    }
}

在Spring框架中的这个单例模式是使用单例设计模式创建Bean的吗?

很显然不是。最显著的一点就是,你在项目中创建的类的构造方法是私有的吗?

Spring 底层创建单例模式的Bean 使用的是BeanFactory工厂设计模式去创建的,在此别混淆了。这种Bean概念更准确的描述应该是Bean的单例作用域

除此之外,Spring框架还提供了其他类型的作用域,比如Prototype原型模式,可以通过 @Scope("prototype") 注解来标注一个bean,这样每次从容器中获取该bean时,容器都会创建一个新的实例。

@Component
@Scope("prototype")
public class MyPrototypeBean {
    // 类的具体代码
}

Prototype原型作用域的Bean对象和原型设计模式有什么关系呢?在原型设计模式中再进行分享。

总结:

单例模式的作用主要包括以下几个方面:

  1. 确保全局唯一实例: 单例模式确保系统中某个类只有一个实例存在,无论在何处进行实例化,都会获得相同的实例。这可以防止多个对象之间的状态不一致或冲突,确保所有使用者操作一致,有助于管理全局资源。
  2. 提供全局访问点: 单例模式提供一个全局访问点,使得任何地方都可以轻松访问该实例。这在需要频繁访问某个对象或共享资源的情况下非常有用,可以简化代码逻辑,提高代码的可读性和可维护性。
  3. 节约系统资源: 由于单例模式只创建一个对象实例,因此可以避免重复创建对象所带来的性能和内存消耗。特别是在频繁访问该对象的场景下,单例模式可以有效减少系统资源的使用。
  4. 控制对象的实例化过程: 单例模式可以对对象的实例化过程进行严格控制,确保只有一个实例存在,并且在运行时动态创建或延迟实例化,以满足特定的需求。这在需要对对象的创建过程进行特殊处理或优化时非常有用。
  5. 避免全局变量的滥用: 单例模式可以将全局状态封装在一个对象中,避免使用大量的全局变量和静态方法,从而提高代码的可维护性和可测试性。

简言之,单例模式在需要确保系统中某个类只有一个实例存在,并且需要提供全局访问点。它可以简化系统架构,提高代码的重用性和可维护性,同时节约系统资源,提高系统性能。但是要注意,线程是否安全的问题。

看了Spring单例作用域的Bean,应该知道一点:

设计模式不是简单地将一个固定的代码框架套用到项目中,而是一种严谨的编程思想,旨在提供解决特定问题的经验和指导。

就单例设计模式来说,控制一个类只有一个实例,并提供一个全局访问点,掌握这个编程思想的应用才是学习设计模式的关键。

在这里插入图片描述

软考中级--软件设计师毫无保留的备考分享

2023年下半年软考考试重磅消息

通过软考后却领取不到实体证书?

计算机算法设计与分析(第5版)

Java全栈学习路线、学习资源和面试题一条龙

软考证书=职称证书?

什么是设计模式?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1968637.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux用户-用户组

作者介绍:简历上没有一个精通的运维工程师。希望大家多多关注我,我尽量把自己会的都分享给大家,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 Linux是一个多用户多任务操作系统,这意味着它可以同时支持多个用户登录并使用系统。…

每日OJ_牛客HJ74 参数解析

目录 牛客HJ74 参数解析 解析代码1 解析代码2 牛客HJ74 参数解析 参数解析_牛客题霸_牛客网 解析代码1 本题通过以空格和双引号为间隔&#xff0c;统计参数个数。对于双引号&#xff0c;通过添加flag&#xff0c;保证双引号中的空格被输出。 #include <iostream> #i…

解决文件夹打不开难题:数据恢复全攻略

在日常的电脑使用过程中&#xff0c;遇到文件夹无法打开的情况无疑是令人头疼的。这不仅可能影响到我们的工作效率&#xff0c;还可能导致重要数据的丢失。本文将深入探讨文件夹打不开的原因&#xff0c;并为您提供两种高效的数据恢复方案&#xff0c;助您轻松应对这一难题。 一…

p33 指针详解(1)(2)(3)

指针的进阶 1.字符指针 void test(int arr[]) { int szsizeof(arr)/sizeof(arr[0]); printf("%d\n", sz); } int main() { int arr[10] {0}; test(arr); return 0; } 这个代码在64位计算机中是8/42 在32位计算机中的是4/41 int main() {char c…

vue2 搭配 html2canvas 截图并设置截图时样式(不影响页面) 以及 base64转file文件上传 或者下载截图 小记

下载 npm install html2canvas --save引入 import html2canvas from "html2canvas"; //使用 html2canvasForChars() { // 使用that来存储当前Vue组件的上下文&#xff0c;以便在回调函数中使用 let that this; // 获取DOM中id为"charts"的元素&…

3.1 拓扑排序

有向图的存储 邻接矩阵 邻接表 拓扑排序 有向无环图&#xff1a;不存在环的有向图 环&#xff1a; 在有向图中&#xff0c;从一个节点出发&#xff0c;最终回到它自身的路径被称为环 入度&#xff1a; 以节点x为终点的有向边的条数被称为x的入度 出度&#xff1a; 以节…

汽车配件销售系统2024

下载在最后,编号ssm007 技术栈: ssmmysqljsp 展示: 下载地址: CSDN现在上传有问题,有兴趣的朋友先收藏.正常了贴上下载地址 备注: 运行有问题请私信我,私信按钮在文章左边) 另外接各种定制系统,java,spring,c,c,python

upload-labs靶场(超详解)1-16关

pass1 从代码中可以看出&#xff0c;是通过js进行文件格式检查 <script type"text/javascript">function checkFile() {var file document.getElementsByName(upload_file)[0].value;if (file null || file "") {alert("请选择要上传的文件…

Nmap/DNS信息收集实验

​实验背景 在安全服务项目中&#xff0c;需要对网络结构进行分析评估&#xff0c;其中风险评估第一步就是信息收集&#xff0c;主要包括活跃主机发现、开放端口号、系统指纹信息等。 实验设备 一个网络 net:cloud0 一台模拟黑客 kali 主机 一台靶机 windows 主机 实验…

go 语言中 init() 函数是什么时候执行的?

文章目录 一、init() 函数什么时候执行&#xff1f;二、init() 函数特点三、代码执行顺序四、多个 init() 函数执行顺序1、一个源文件中多个 init() 函数2、一个包中多个 init() 函数3、多个包中多个 init() 函数&#xff08;不存在依赖&#xff09;4、多个包中多个 init() 函数…

MySQL--数据类型

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 在MySQL数据库管理系统中&#xff0c;可以通过存储引擎来决定表的类型。同时&#xff0c;MySQL数据库管理系统也提供了数据类型决定表存储数据的类型 …

记录导致计算轮廓面积出错的一个坑点

1.前言 计算轮廓面积是常见的几何算法话题&#xff0c;获取轮廓面积、计算轮廓法线等场景会涉及到。计算轮廓面积的方法有很多&#xff0c;一种常用的是微积分思路的分段求和办法&#xff0c;即组成轮廓的每条线段与X轴或Y轴进行有向投影&#xff0c;轮廓边线与X轴或Y轴的投影之…

【SQL Server】SQL Server基础知识概览

目录 第1章&#xff1a;SQL Server 概览 SQL Server 版本介绍 SQL Server 架构 SQL Server 组件 第1章&#xff1a;SQL Server 概览 SQL Server 版本介绍 SQL Server 是 Microsoft 开发的一款关系型数据库管理系统 (RDBMS)&#xff0c;广泛应用于企业级数据存储和处理场景…

Mysql学习-day15

Mysql学习-day15 1. 行列转换 在MySQL中&#xff0c;行列转换可以通过使用CASE语句结合聚合函数来实现。 表t_score数据如图所示 我们想要以学科为列名&#xff0c;展示每个学生的科目成绩&#xff0c;可以先用CASE语句来选出每科的成绩&#xff0c;再进行求和。 选择科目时…

【C++】模拟实现list

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 目录 一.了解项目及其功能 &#x1f4cc;了解list官方标准 了解模拟实现list &#x1f4cc;了解更底层的list实现 二.list迭代器和vector迭代器的异同 &#x1f4cc;迭代…

SSH实现电脑VScode免密登录到虚拟机其原理

在网上想看一下这个原理。发现写的还是比较乱&#xff0c;所以自己总结了一份方便回顾 SSH免密登录的原理主要基于非对称密钥加密技术&#xff0c;比较常用的是RSA算法。 以下是SSH免密登录的详细步骤和原理&#xff1a; 1. 生成密钥对 在客户端上生成一对密钥&#xff0c;…

系统复习Java日志体系

一&#xff0c;我们采用硬编码体验一下几个使用比较多的日志 分别导入几种日志的 jar 包 <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSch…

【已解决】YOLOv8加载模型报错:super().__init__(torch._C.PyTorchFileReader(name_or_buffer))

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

C#——Json数据存储

本文使用的软件为VS2022&#xff0c;不同的软件使用上有些许差异。 C#数据存储 关于数据存储&#xff0c;一般在退出控制台之后&#xff0c;暂存的数据都会释放掉&#xff0c;有没有什么方法能够在下一次进入的时候还能加载上一次的数据呢&#xff1f;答案是有的&#xff0c;关…

利用Arcgis设置分式标注(分子分母标注)

因工作需要&#xff0c;需要设置分式标注&#xff0c;下面详细介绍下如何利用arcgis 设置分式标注&#xff0c;以下操作以供参考&#xff0c;如有疑义可提出。 一、准备工作 软件&#xff1a;arcmap 示例数据&#xff1a;行政区shp矢量图 二、操作步骤 1.添加数据 将行政区sh…