Java基础:单例模式,Spring源码中有哪些单例模式

单例模式是一种常用的软件设计模式,其目的是确保一个类仅有一个实例,并提供一个全局访问点来获取这个唯一实例。在Java中,实现单例模式通常需要遵循以下几个关键原则:

  1. 私有化构造器:将类的构造器声明为private,以防止外部代码通过new操作符直接创建该类的实例。

  2. 静态工厂方法:提供一个静态方法(通常称为getInstance()),用于获取单例对象。这个方法负责检查是否已经创建过实例,如果尚未创建,则创建并保存;如果已存在,则直接返回该实例。

  3. 确保线程安全:在多线程环境中,必须确保单例对象的创建过程是线程安全的,即无论何时何地,无论多少个线程同时请求,都只会创建一个实例。

以下是几种常见的Java单例模式实现方式及其示例:

1. 饿汉式(静态常量)

优点:类加载时即初始化单例,线程安全,无同步开销。

缺点:如果单例实例很庞大或创建过程耗时,可能会导致类加载时较长的初始化时间,且即使从未使用该单例,也会占用内存。

public class SingletonEager {private static final SingletonEager INSTANCE = new SingletonEager();private SingletonEager() {}public static SingletonEager getInstance() {return INSTANCE;}
}

2. 懒汉式(线程不安全)

优点:延迟初始化,只有在首次调用getInstance()时才创建单例。

缺点:线程不安全,多线程环境下可能创建多个实例。

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

3. 懒汉式(线程安全,同步方法)

优点:解决了线程安全问题。

缺点:每次调用getInstance()都会进行同步,造成不必要的性能损耗。

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

4. 双重检查锁定(DCL, Double-Checked Locking)

优点:既实现了延迟初始化,又保证了线程安全,且仅在初始化时加锁,性能较高。

缺点:依赖JVM正确实现内存模型,早期JVM版本可能存在DCL失效问题,但在现代JVM中已得到解决。

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

5. 静态内部类

优点:利用类加载机制保证线程安全,延迟初始化,无同步开销。

缺点:相比其他实现方式,代码结构稍显复杂。

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

分析Spring源码中的单例模式及作用

Spring框架广泛使用了单例模式,尤其是在其核心组件BeanFactory中管理的bean实例。Spring默认将配置文件中定义的bean配置为单例模式,这意味着对于每个指定为单例的bean,Spring容器在整个应用程序生命周期中仅创建一次该bean的实例,并将其缓存起来,后续对该bean的所有请求都将返回相同的实例。

作用:

  1. 资源优化:对于重量级、高消耗资源的对象(如数据库连接、线程池等),通过单例模式限制实例数量,避免资源浪费。
  2. 一致性保证:对于需要保持全局唯一状态或共享状态的bean,单例模式确保所有客户端共享同一份实例,从而维持状态的一致性。
  3. 简化编程模型:开发者无需关心bean实例的创建、管理和销毁,只需关注业务逻辑,降低了代码耦合度。

由于Spring源码庞大且涉及众多模块,这里无法直接给出全部相关源码。但可以简述Spring如何实现单例模式:

Spring的DefaultListableBeanFactory类(或其他实现BeanFactory接口的类)是Spring IoC容器的核心实现,它维护了一个DefaultSingletonBeanRegistry(或类似实现SingletonBeanRegistry接口的类)来管理单例bean。当容器创建一个bean时,首先检查是否已经存在该bean的单例实例。如果存在,直接从缓存中返回;否则,按照bean定义创建新实例,并将其放入缓存中。

以下是一段简化版的伪代码,以说明Spring如何通过SingletonBeanRegistry来实现单例模式:

public interface BeanFactory {Object getBean(String beanName);
}public interface SingletonBeanRegistry {Object getSingleton(String beanName);void registerSingleton(String beanName, Object singletonObject);
}public class DefaultListableBeanFactory implements BeanFactory {private final SingletonBeanRegistry singletonRegistry;public Object getBean(String beanName) {return this.singletonRegistry.getSingleton(beanName);}
}public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>();public Object getSingleton(String beanName) {return this.singletonObjects.get(beanName);}public void registerSingleton(String beanName, Object singletonObject) {this.singletonObjects.putIfAbsent(beanName, singletonObject);}
}

实际Spring源码中,DefaultSingletonBeanRegistry及其相关类还包含了许多额外逻辑,如处理循环依赖、bean的后置处理器、生命周期回调等。以上伪代码仅为了说明Spring如何通过一个注册表(registry)来管理单例bean的创建和缓存,确保整个应用中每个bean名称对应唯一实例。

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

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

相关文章

学习Rust的第11天:模块系统

Rust的模块系统可以使用它来管理不断增长的项目&#xff0c;并跟踪 modules 存储在何处。 Rust的模块系统是将代码组织成逻辑片段的有效工具&#xff0c;因此可以实现代码维护和重用。模块支持分层组织、隐私管理和代码封装。Rust为开发人员提供了多功能和可扩展的方法来管理项…

用 Pytorch 训练一个 Transformer模型

昨天说了一下Transformer架构&#xff0c;今天我们来看看怎么 Pytorch 训练一个Transormer模型&#xff0c;真实训练一个模型是个庞大工程&#xff0c;准备数据、准备硬件等等&#xff0c;我只是做一个简单的实现。因为只是做实验&#xff0c;本地用 CPU 也可以运行。 本文包含…

Vue阶段练习:tab栏、进度条、

阶段练习旨在学习完Vue 指令、计算属性、侦听器-CSDN博客后&#xff0c;进行自我检测&#xff0c;每个练习分为效果显示、需求分析、静态代码、完整代码、总结 四个部分&#xff0c;效果显示和准备代码已给出&#xff0c;我们需要完成“完整代码”部分。 练习1&#xff1a;tab栏…

开源大数据集群部署(二十一)Spark on yarn 部署

作者&#xff1a;櫰木 1 spark on yarn安装&#xff08;每个节点&#xff09; cd /root/bigdata/ tar -xzvf spark-3.3.1-bin-hadoop3.tgz -C /opt/ ln -s /opt/spark-3.3.1-bin-hadoop3 /opt/spark chown -R spark:spark /opt/spark-3.3.1-bin-hadoop32 配置环境变量及修改配…

攻防世界---misc---再见李华

1.下载附件是解压之后得到一张图片 2.使用常规方法后没有得到什么信息&#xff0c;接着用winhex分析&#xff0c;发现有压缩包 &#xff0c;里面还有个key.txt 3.接着用kali使用命名foremost进行分离&#xff0c;得到压缩包&#xff0c;里面的key.txt需要密码 4.接着给压缩包暴…

IDEA代码重构

重构 重构的目的&#xff1a; 提高代码的可读性、可维护性、可扩展性和性能。 重命名元素 重命名类 当我们进行重命名操作的时候可以看到第六行存在一个R(rename)&#xff0c;点击后就会弹出所偶有引用&#xff0c;这样可以避免我们在修改后存在遗漏引用处未修改。 我们可以通过…

管理集群工具之LVS

管理集群工具之LVS 集群概念 将很多机器组织在一起&#xff0c;作为一个整体对外提供服务集群在扩展性、性能方面都可以做到很灵活集群分类 负载均衡集群&#xff1a;Load Balance高可用集群&#xff1a;High Availability高性能计算&#xff1a;High Performance Computing …

模拟网关是什么?

模拟网关是一种网络设备&#xff0c;用于在模拟电话系统和数字网络之间进行信号转换。它的主要作用是将模拟语音信号转换为数字格式&#xff0c;使得这些信号能够通过基于IP&#xff08;互联网协议&#xff09;的网络进行传输&#xff0c;从而实现语音通信。这种设备是将传统的…

Python环境找不到解决方法

Python环境找不到 打开设置&#xff1a;Ctrl Alt S 添加Local Interpreter... 打开System Interpreter&#xff0c;找到本地安装的Python.exe路径&#xff0c;然后一路点OK Trust Project 如果打开工程时&#xff0c;出现如下对话框&#xff0c;请勾选 Trust projects in ...&…

项目管理中,项目团队如何高效的协作与沟通?

目 录 一、项目团队高效的协作与沟通&#xff0c;可以通过以下几个方面来实现&#xff1a; 二、如何在项目团队中明确和共享愿景以提高协作效率&#xff1f; 三、有效的沟通策略在项目管理中的应用案例有哪些&#xff1f; 四、建立哪些具体的沟通机制可以提升团队协作效率…

matlab学习003-绘制由差分方程表示的离散系统图像

目录 1&#xff0c;题目 2&#xff0c;使用函数求解差分方程 1&#xff09;基础知识 ①filter函数和impz函数 ②zeros函数 ☀ 2&#xff09;绘制图像 ​☀ 3&#xff09;对应代码 如果连简单的信号都不会的&#xff0c;建议先看如下文章&#x1f447;&#xff0c;之…

互联网大厂ssp面经,数据结构part2

1. 什么是堆和优先队列&#xff1f;它们的特点和应用场景是什么&#xff1f; a. 堆是一种特殊的树形数据结构&#xff0c;具有以下特点&#xff1a;i. 堆是一个完全二叉树&#xff0c;即除了最后一层外&#xff0c;其他层都是满的&#xff0c;并且最后一层的节点都靠左对齐。i…

SEGGER Embedded Studio IDE移植FreeRTOS

SEGGER Embedded Studio IDE移植FreeRTOS 一、简介二、技术路线2.1 获取FreeRTOS源码2.2 将必要的文件复制到工程中2.2.1 移植C文件2.2.2 移植portable文件2.2.3 移植头文件 2.3 创建FreeRTOSConfig.h并进行配置2.3.1 处理中断优先级2.3.2 configASSERT( x )的处理2.3.3 关于系…

linq select 和selectMany的区别

Select 和 SelectMany 都是 LINQ 查询方法&#xff0c;但它们之间有一些区别。 Select 方法用于从集合中选择特定的属性或对集合中的元素进行转换&#xff0c;并返回一个新的集合。例如&#xff1a; var numbers new List<int> { 1, 2, 3, 4, 5 }; var squaredNumbers…

SRS WebRTC Whip 和 Whep 部署体验问题

whip 報錯 404 webrtc推流 小窗口一闪而过&#xff0c;然后查看f12回复404的报错信息 chrome版本&#xff1a; 正在检查更新 版本 123.0.6312.123&#xff08;正式版本&#xff09; &#xff08;64 位&#xff09; centos 7.9 源码安装部署&#xff0c; 代码分支5.0 完全按…

socket通信基础讲解及示例-C

socket通信之C篇 服务端与客户端简介 socket通信服务端与客户端通信模型通信实战server&#xff08;服务端&#xff09;创建client&#xff08;客户端&#xff09;创建 函数详解创建套接字 socket绑定端口bind进入监听状态listen获取客户端连接请求accept接收网络数据read发送数…

每日一题---移除链表元素

文章目录 前言1.题目2.分析思路3.参考代码 前言 Leetcode–-移除链表元素 1.题目 2.分析思路 首先要创建一个新的链表&#xff0c;在定义三个指针&#xff0c;newHead&#xff0c;newTail和pcur&#xff0c;分别代表新链表头&#xff0c;新链表尾以及用于遍历原链表。 其次是…

Rust入门-所有权

一、为什么、是什么、怎么用 1、为什么Rust要提出一个所有权和借用的概念 所有的程序都必须和计算机内存打交道&#xff0c;如何从内存中申请空间来存放程序的运行内容&#xff0c;如何在不需要的时候释放这些空间&#xff0c;成为所有编程语言设计的难点之一。 主要分为三种…

git merge 和 git rebese的区别

git merge 和 git rebese的区别 拉取分支和合并代码会涉及两种选择&#xff0c;git merge 和 git rebase&#xff1a; rebase&#xff1a;变基&#xff0c;会有一个干净的分支&#xff0c;但是对于记录来源不够清楚merge&#xff1a;合并&#xff0c;git 分支看起来比较混乱&…

CentOS 7虚拟机配置静态IP地址(一)

IP地址的配置 以下几个地址需要记住&#xff0c;在配置中使用 &#xff08;1&#xff09;查看MAC地址&#xff08;点击菜单虚拟机-设置-网络适配器-高级-记住MAC地址&#xff09; &#xff08;2&#xff09;查看子网掩码和网关IP&#xff08;点击菜单编辑-虚拟网络编辑器-选择…