当前位置: 首页 > article >正文

【Spring】单例模式的创建方式(Bean解析)

在Java中,单例模式(Singleton Pattern)确保一个类只有一个实例,并提供全局访问点。以下是实现单例的五种常见方式:懒汉式饿汉式双重检查锁静态内部类枚举,包括代码示例和优缺点分析。


1. 懒汉式(Lazy Initialization)

  • 特点:延迟加载,实例在第一次使用时创建。
  • 线程安全:基本实现非线程安全,需加锁优化。
  • 代码示例
    public class Singleton {private static Singleton instance;private Singleton() {} // 私有构造,防止外部实例化public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
    }
    
    • 线程安全版(加锁):
      public class Singleton {private static Singleton instance;private Singleton() {}public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
      }
      
  • 优点
    • 延迟加载,节省内存(只有在使用时才创建实例)。
  • 缺点
    • 基本版线程不安全。
    • 线程安全版使用synchronized方法锁,性能较低(每次调用都加锁)。
  • 适用场景:单线程环境或实例创建开销小、对性能要求不高的场景。

2. 饿汉式(Eager Initialization)

  • 特点:类加载时就创建实例,急切初始化。
  • 线程安全:天然线程安全,依赖JVM类加载机制。
  • 代码示例
    public class Singleton {private static final Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}
    }
    
  • 优点
    • 实现简单,线程安全(由JVM类加载保证)。
    • 无需加锁,性能较高。
  • 缺点
    • 非延迟加载,类加载时即创建实例,可能浪费内存(如果实例未被使用)。
    • 如果构造方法有复杂逻辑,类加载可能变慢。
  • 适用场景:实例创建开销小、确定会被使用的场景。

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

  • 特点:结合懒汉式的延迟加载和线程安全,减少锁粒度。
  • 线程安全:通过volatile和双重检查确保线程安全。
  • 代码示例
    public class Singleton {private static volatile Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) { // 第一次检查(无锁)synchronized (Singleton.class) {if (instance == null) { // 第二次检查(有锁)instance = new Singleton();}}}return instance;}
    }
    
  • 关键点
    • volatile防止指令重排序,确保实例初始化完成前不被其他线程访问。
    • 双重检查减少锁竞争,仅在实例未创建时加锁。
  • 优点
    • 延迟加载,节省内存。
    • 线程安全,性能较高(锁粒度小)。
  • 缺点
    • 实现较复杂,需理解volatile和指令重排序。
    • 早期Java版本(1.4及之前)可能有DCL失效问题(现已解决)。
  • 适用场景:需要延迟加载且高并发的场景。

4. 静态内部类(Static Inner Class)

  • 特点:利用JVM类加载机制实现延迟加载和线程安全。
  • 线程安全:由JVM保证静态内部类加载时的线程安全。
  • 代码示例
    public class Singleton {private Singleton() {}private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}public static Singleton getInstance() {return SingletonHolder.INSTANCE;}
    }
    
  • 原理
    • 静态内部类SingletonHoldergetInstance()调用时才加载,触发INSTANCE初始化。
    • JVM确保类加载过程线程安全,无需额外同步。
  • 优点
    • 延迟加载,节省内存。
    • 线程安全,无需加锁,性能高。
    • 实现优雅,代码简洁。
  • 缺点
    • 无法传递参数给构造方法(除非通过其他方式)。
  • 适用场景:需要延迟加载且要求高性能的场景,推荐使用。

5. 枚举(Enum)

  • 特点:使用Java枚举类型实现单例,简洁且天然线程安全。
  • 线程安全:由JVM保证枚举实例的单例性。
  • 代码示例
    public enum Singleton {INSTANCE;// 可添加方法public void doSomething() {System.out.println("Singleton method called");}
    }
    
    • 使用方式:
      Singleton.INSTANCE.doSomething();
      
  • 优点
    • 实现最简单,代码极少。
    • 线程安全,由JVM保证。
    • 防止反射攻击和序列化问题(枚举天生防止反序列化创建新实例)。
    • 支持添加方法,功能灵活。
  • 缺点
    • 非延迟加载,枚举类加载时即创建实例。
    • 不支持复杂构造逻辑(枚举构造较为固定)。
  • 适用场景:需要绝对线程安全、防止反射/序列化问题、逻辑简单的场景。

6. 对比总结

方式延迟加载线程安全性能复杂性防止反射/序列化适用场景
懒汉式否/是(加锁)低(锁)需额外处理单线程或低并发
饿汉式需额外处理确定使用、无内存限制
双重检查锁需额外处理高并发、延迟加载
静态内部类需额外处理高性能、延迟加载,推荐
枚举天然支持简单逻辑、防反射/序列化,推荐

7. 注意事项

  • 私有构造:所有实现都需私有构造方法,防止外部实例化。
  • 反射攻击:除枚举外,其他方式可能通过反射创建实例,需在构造方法中加防护:
    private Singleton() {if (instance != null) {throw new RuntimeException("Instance already exists!");}
    }
    
  • 序列化问题:除枚举外,单例实现序列化时需实现readResolve方法:
    private Object readResolve() {return instance;
    }
    
  • Spring中的单例:Spring的单例是容器级别的,生命周期由Spring管理,通常无需手动实现单例模式。

8. 推荐方式

  • 首选静态内部类(延迟加载、线程安全、实现优雅)。
  • 次选枚举(最简单、防反射/序列化,适合简单场景)。
  • 高并发双重检查锁(需确保正确使用volatile)。
  • 确定使用饿汉式(简单直接)。
  • 避免懒汉式(除非单线程或加锁优化)。

相关文章:

【Spring】单例模式的创建方式(Bean解析)

在Java中,单例模式(Singleton Pattern)确保一个类只有一个实例,并提供全局访问点。以下是实现单例的五种常见方式:懒汉式、饿汉式、双重检查锁、静态内部类和枚举,包括代码示例和优缺点分析。 1. 懒汉式&am…...

关于hadoop和yarn的问题

1.hadoop的三大结构及各自的作用? HDFS(Hadoop Distributed File System):分布式文件系统,负责海量数据的存储,具有高容错性和高吞吐量。 MapReduce:分布式计算框架,用于并行处理大…...

【飞渡科技数字孪生虚拟环境部署与集成教程 - CloudMaster实战指南】

飞渡科技数字孪生虚拟环境部署与集成教程 - CloudMaster实战指南 前言 本教程详细记录了飞渡科技的数字孪生平台CloudMaster的配置过程,以及如何将三维数字孪生场景集成到前端项目中。数字孪生技术能够在虚拟环境中精确复现物理实体的数据、特性和行为&#xff0c…...

计算机软考中级 知识点记忆——排序算法 冒泡排序-插入排序- 归并排序等 各种排序算法知识点整理

一、📌 分类与比较 排序算法 最优时间复杂度 平均时间复杂度 最坏时间复杂度 空间复杂度 稳定性 应用场景与特点 算法策略 冒泡排序 O(n) O(n) O(n) O(1) 稳定 简单易实现,适用于小规模数据排序。 交换排序策略 插入排序 O(n) O(n) O…...

第十五届蓝桥杯 2024 C/C++组 下一次相遇

目录 题目: 题目描述: 题目链接: 思路: 自己的思路详解: 更好的思路详解: 代码: 自己的思路代码详解: 更好的思路代码详解: 题目: 题目描述&#xf…...

【2】CICD持续集成-k8s集群中安装Jenkins

一、背景: Jenkins是一款开源 CI&CD 系统,用于自动化各种任务,包括构建、测试和部署。 Jenkins官方提供了镜像:https://hub.docker.com/r/jenkins/jenkins 使用Deployment来部署这个镜像,会暴露两个端口&#xff…...

监控+日志=DevOps 运维的“千里眼”与“顺风耳”

监控+日志=DevOps 运维的“千里眼”与“顺风耳” 在 DevOps 体系中,监控和日志管理是不可或缺的运维基石。有人说,开发只管把代码写好,运维才是真正的“操盘手”,让系统稳定运行、不宕机、不崩溃。而要做到这一点,精准的监控与日志管理 是关键。 试想一下:如果没有监控…...

安卓的Launcher 在哪个环节进行启动

安卓Launcher在系统启动过程中的关键环节启动,具体如下: 内核启动:安卓设备开机后,首先由引导加载程序启动Linux内核。内核负责初始化硬件设备、建立内存管理机制、启动系统进程等基础工作,为整个系统的运行提供底层支…...

IDEA 创建Maven 工程(图文)

设置Maven 仓库 打开IDEA 开发工具,我的版本是2024.3.1(每个版本的位置不一样)。在【Customize】选项中,可以直接设置【语言】,在最下面选择【All setting】。 进入到熟悉的配置界面,选择配置的【setting…...

映射(Mapping)和地址(Address)

Addresses (地址) 以太坊区块链由 _ account _ (账户)组成,你可以把它想象成银行账户。一个帐户的余额是 以太 (在以太坊区块链上使用的币种),你可以和其他帐户之间支付和接受以太币,就像你的银…...

通过C# 将Excel表格转换为图片(JPG/ PNG)

Excel 表格可能会因为不同设备、不同软件版本或字体缺失等问题,导致格式错乱或数据显示异常。转换为图片后,能确保数据的排版、格式和外观始终保持一致,无论在何种设备或平台上查看,都能呈现出固定的样式,避免了因环境…...

国产紫光同创FPGA实现SDI视频编解码+图像缩放,基于HSSTHP高速接口,提供2套工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的所有工程源码总目录----方便你快速找到自己喜欢的项目本博已有的 SDI 编解码方案本方案在Xilinx--Artix7系列FPGA上的应用本方案在Xilinx--Kintex系列FPGA上的应用本方案在Xilinx--Zynq系列FPGA上的应用本方案在Xilinx--U…...

day46—双指针-两数之和-输入有序数组(LeetCode-167)

题目描述 给你一个下标从 1 开始的整数数组 numbers &#xff0c;该数组已按 非递减顺序排列 &#xff0c;请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] &#xff0c;则 1 < index1 < index2 &l…...

自动驾驶安全模型研究

自动驾驶安全模型研究 自动驾驶安全模型研究 自动驾驶安全模型研究1.自动驾驶安全模型概述2. 自动驾驶安全模型应用3. 自动驾驶安全模型介绍3.1 Last Point to Steer3.2 Safety Zone3.3 RSS (Responsibility-Sensitive Safety)3.4 SFF (Safety Force Field)3.5 FSM (Fuzzy Safe…...

【项目】基于MCP+Tabelstore架构实现知识库答疑系统

基于MCPTabelstore架构实现知识库答疑系统 整体流程设计&#xff08;一&#xff09;Agent 架构&#xff08;二&#xff09;知识库存储&#xff08;1&#xff09;向量数据库Tablestore&#xff08;2&#xff09;MCP Server &#xff08;三&#xff09;知识库构建&#xff08;1&a…...

当OCR遇上“幻觉”:如何让AI更靠谱地“看懂”文字?

在数字化的世界里&#xff0c;OCR&#xff08;光学字符识别&#xff09;技术就像给机器装上了“电子眼”。但当这项技术遇上大语言模型&#xff0c;一个意想不到的问题出现了——AI竟然会像人类一样产生“幻觉”。想象一下&#xff0c;当你拿着模糊的财务报表扫描件时&#xff…...

Docker用model.config部署及更新多个模型

步骤&#xff1a; 1、本地打包模型 2、编写model.config文件 3、使用 Docker 启动一个 TensorFlow Serving 容器 4、本地打包后的模型修改后&#xff0c;修改本地model.config&#xff0c;再同步更新容器的model.config 1、本地打包模型&#xff08;本地路径&#xff09; 2、…...

Linux kernel signal原理(下)- aarch64架构sigreturn流程

一、前言 在上篇中写到了linux中signal的处理流程&#xff0c;在do_signal信号处理的流程最后&#xff0c;会通过sigreturn再次回到线程现场&#xff0c;上篇文章中介绍了在X86_64架构下的实现&#xff0c;本篇中介绍下在aarch64架构下的实现原理。 二、sigaction系统调用 #i…...

matlab论文图一的地形区域图的球形展示Version_1

matlab论文图一的地形区域图的球形展示Version_1 图片 此图来源于&#xff1a; ![Jieqiong Zhou, Ziyin Wu, Dineng Zhao, Weibing Guan, Chao Zhu, Burg Flemming, Giant sand waves on the Taiwan Banks, southern Taiwan Strait: Distribution, morphometric relationship…...

发布一个npm包,更新包,删除包

发布一个npm包&#xff0c;更新包&#xff0c;删除包 如何将自己的项目 发布为一个 npm 包&#xff0c;并掌握 更新 和 删除 的操作流程。 &#x1f680; 一、发布一个 npm 包的完整流程 ✅ 1. 注册并登录 npm 账号 如果还没有账号&#xff0c;先注册&#xff1a; 官网注册&…...

Redis专题

前言 Redis的各种思想跟机组Cache和操作系统对进程的管理非常类似&#xff01; 一&#xff1a;看到你的简历上写了你的项目里面用到了redis&#xff0c;为啥用redis&#xff1f; 因为传统的关系型数据库如Mysql,已经不能适用所有的场景&#xff0c;比如秒杀的库存扣减&#xff…...

LeetCode[232]用栈实现队列

思路&#xff1a; 一道很简单的题&#xff0c;就是栈是先进后出&#xff0c;队列是先进先出&#xff0c;用两个栈底相互对着&#xff0c;这样一个队列就产生了&#xff0c;右栈为空的情况&#xff0c;左栈栈底就是队首元素&#xff0c;所以我们需要将左栈全部压入右栈&#xff…...

Flask API 项目 Swagger 版本打架不兼容

Flask API 项目 Swagger 版本打架不兼容 1. 问题背景 在使用 Flask 3.0.0 时遇到以下问题&#xff1a; 安装 flask_restful_swagger 时&#xff0c;它强制将 Flask 降级到 1.1.4&#xff0c;并导致其他依赖&#xff08;如 flask-sqlalchemy、flask-apispec&#xff09;出现版…...

基于YOLOv11 和 ByteTrack 实现目标跟踪

介 绍 之前我们介绍了使用YOLOv9与 ByteTrack 结合进行对象跟踪的概念&#xff0c;展示了这两种强大的技术如何有效地协同工作。现在&#xff0c;让我们通过探索与 ByteTrack 结合的 YOLOv11 来进一步了解这一概念。 实战 | 基于YOLOv9和OpenCV实现车辆跟踪计数&#xff08;步骤…...

Qt Creator 创建 Qt Quick Application一些问题

一、Qt Creator 创建 Qt Quick Application 时无法选择 MSVC 编译器(即使已安装 Qt 5.15.2 和 MSVC2019) 1、打开 Qt Creator 的编译器设置 工具 (Tools) → 选项 (Options) → Kits → 编译器 (Compilers) 检查是否存在 Microsoft Visual C++ Compiler (x86_amd64) 或类似条…...

编码转换器

大批量转换编码 可以将整个工程文件夹从GB18030转为UTF-8 使用Qt C制作 项目背景 比较老的工程&#xff0c;尤其是keil嵌入式的工程&#xff0c;其文本文件&#xff08;.c、.cpp、.h、.txt、……&#xff09;编码为gb2312&#xff0c;这为移植维护等带来了不便。现在uit-8用…...

Django 中集成 Apache Kafka 可以实现异步消息处理、数据流式传输

在 Django 中集成 Apache Kafka 可以实现异步消息处理、数据流式传输等功能,以下是详细的集成步骤和示例代码: 1. 安装必要的库 首先,你需要安装 kafka-python 库,它是 Python 中操作 Kafka 的常用库。可以使用以下命令进行安装: pip install kafka-python2. 配置 Kafk…...

Scala 入门指南

Scala 入门指南 目录 简介环境搭建基础语法面向对象编程函数式编程集合模式匹配特质隐式转换并发编程与 Java 互操作最佳实践常见问题 简介 Scala 是一种多范式编程语言&#xff0c;结合了面向对象编程和函数式编程的特性。它运行在 JVM 上&#xff0c;与 Java 完全兼容&am…...

[密码学实战]密评考试训练系统v1.0程序及密评参考题库(获取路径在文末)

[密码学实战]密评考试训练系统v1.0程序及密评参考题库 引言:密评考试的重要性与挑战 商用密码应用安全性评估(简称"密评") 作为我国密码领域的重要认证体系,已成为信息安全从业者的必备技能。根据国家密码管理局最新数据,截至2024年6月,全国仅有3000余人持有…...

【Rust 精进之路之第6篇-流程之舞】控制流:`if/else`, `loop`, `while`, `for` 与模式匹配初窥

系列: Rust 精进之路:构建可靠、高效软件的底层逻辑 作者: 码觉客 发布日期: 2025-04-20 引言:让代码“活”起来——指令的流动 在前面的文章中,我们已经掌握了 Rust 的基础数据类型(标量和复合类型)以及如何通过变量绑定来存储和命名它们。这相当于我们准备好了程序…...