单例模式及其思想

news/2024/9/18 7:00:35/文章来源:https://www.cnblogs.com/dennyLee2025/p/18337717

本文包括以下几点↓

在这里插入图片描述

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

单例模式(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 {@Beanpublic 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.hqwc.cn/news/776366.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数组part02

2024年8月1日,今天学习了数组的第二部分。 1.巩固了昨天的双指针问题,即滑动窗口/双指针;注意,双指针是为了减少for循环,使用的时候小心循环的写法和快慢指针的增长方法。 2.学习了数组模拟的螺旋矩阵问题,注意循环不变量; 3.学习了前缀和的方法,前缀和常用来解决区间和…

windwos文件句柄数限制

1、修改注册表,位置如下: HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Windows2、设置 1、GDIProcessHandleQuota此项设置GDI句柄数量,默认值为2710(16进制)/10000(10进制),该值的允许范围为 256 ~ 16384 ,将其调整为大于默认的10000的值。如果您的…

P5665 [CSP-S2019] 划分

讲解 P5665 [CSP-S2019] 划分。由朴素 dp 入手,先用二分优化,然后用走指针优化,之后注意到单调性,将状态数压缩,然后使用单调队列优化转移。思路: 首先求出 \(a\) 的前缀和数组 \(s\)。 考虑动态规划,令 \(dp_{i,j}\) 表示以 \(i\) 结尾,末尾有 \(j\) 个为一组的最小答…

「代码随想录算法训练营」第二十六天 | 贪心算法 part4

452. 用最少数量的箭引爆气球题目链接:https://leetcode.cn/problems/minimum-number-of-arrows-to-burst-balloons/ 题目难度:中等 文章讲解:https://programmercarl.com/0452.用最少数量的箭引爆气球.html 视频讲解:https://www.bilibili.com/video/BV1SA41167xe 题目状态…

dbnet crnn java中文ocr识别

Table of ContentsAbout Getting Started Result ContactAbout完整项目:https://github.com/jiangnanboy/dbnet_crnn_java本项目利用java,javacv,onnx以及djl矩阵计算等技术加载文本检测模型dbnet与文本识别模型crnn,完成ocr的识别推理。 包含模型的完整项目请从右侧releases…

变量及标识符

变量 变量的概念 内存中的一个存储区域 该区域的数据可以在同一类型范围内不断变化 变量是程序中最基本的存储单元。包含变量类型、变量名和存储的值 变量的作用: 用于在内存中保存数据 使用变量注意: Java中每个变量必须先声明,后使用 使用变量名来访问这块区域的数据 变量…

如何通过PowerShell批量修改O365用户的office phone属性值

我的博客园:https://www.cnblogs.com/CQman/ 如何通过PowerShell批量修改O365用户的office phone属性值? 需求信息:组织中的O365用户在创建时,已手动录入了办公电话(Office phone),现在需要在办公电话前面加上统一的数字,如“0571-0985”,以批量的方式统一修改。 备注:…

1000W长连接,如何建立和维护?千万用户IM 架构设计

文章很长,且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录 博客园版 为您奉上珍贵的学习资源 : 免费赠送 :《尼恩Java面试宝典》 持续更新+ 史上最全 + 面试必备 2000页+ 面试必备 + 大厂必备 +涨薪必备 免费赠送 :《尼恩技术圣经+高并发系列PDF》 ,帮你 实现技术自由,…

封装,private关键字,this关键字

我们上一个案例,使用private关键字将成员进行修饰,外界无法直接访问,讲了那么长时间,实际上就是在传输一个思想面向对象编程的三大特征,第一大特征:封装封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。private关键字:1、被private修饰的成员,外界无法直…

Anaconda 常用命令

1.检查Anaconda是否成功安装:conda --version2.检测目前安装了哪些环境:conda info --envs3.检查目前有哪些版本的python可以安装:conda search --full-name python4.安装不同版本的python:conda create --name tensorflow python=3.75.按照提示,激活python环境:activate…