单例模式(Singleton Pattern)详解


一、单例模式简介

单例模式(Singleton Pattern) 是一种 创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。(对象创建型模式)

简单来说,就是:

“在整个应用程序中,某个类只能有一个对象存在。”

这在需要共享资源、统一管理状态或控制访问时非常有用。

在这里插入图片描述
要点
某个类只能有一个实例
必须自行创建这个实例
必须自行向整个系统提供这个实例

单例模式只包含一个单例角色
Singleton(单例)

在这里插入图片描述


私有构造函数
静态私有成员变量(自身类型)
静态公有的工厂方法

二、解决的问题类型

单例模式主要用于解决以下问题:

  • 多个对象造成资源浪费:比如数据库连接池、线程池等,如果每次使用都新建对象,会造成性能浪费。
  • 需要全局唯一访问入口:如配置管理器、日志记录器等,希望整个系统中都通过同一个接口访问。
  • 避免重复初始化带来的错误:例如缓存服务、任务调度器等,不允许多个实例同时运行。

三、使用场景

场景示例
配置中心ConfigManager 管理应用的配置信息
日志记录器Logger 实现统一的日志输出
数据库连接池DataSource 提供连接复用
缓存服务CacheManager 统一管理缓存数据
线程池管理ExecutorService 控制并发资源

四、实际生活案例

想象你在家里只有一台电视遥控器。无论你是爸爸、妈妈还是孩子,大家都必须通过这一个遥控器来操作电视。如果你允许每个家庭成员都拥有自己的遥控器,那么可能会出现混乱操作和资源浪费。

在这个例子中,“遥控器”就是一个“单例”,全家人共享一个实例。


五、代码案例(Java)

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

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

在这里插入图片描述

⚠️ 注意:这种方式在多线程环境下可能创建多个实例。


2. 懒汉式 + 同步方法(线程安全)

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

优点:线程安全
缺点:效率低,每次调用 getInstance() 都会加锁


多个线程同时访问将导致创建多个单例对象!怎么办?👇👇👇

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

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

优点:线程安全、性能较好
推荐方式之一


4. 饿汉式(静态常量)

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

在这里插入图片描述

优点:实现简单、线程安全
缺点:类加载时就初始化,可能造成资源浪费


5. 静态内部类(推荐写法)

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

优点:懒加载、线程安全、简洁高效
最推荐写法之一


饿汉式单例类与懒汉式单例类比较

饿汉式单例类:无须考虑多个线程同时访问的问题;调用速度和反应时间优于懒汉式单例;资源利用效率不及懒汉式单例;系统加载时间可能会比较长
懒汉式单例类:实现了延迟加载;必须处理好多个线程同时访问的问题;需通过双重检查锁定等机制进行控制,将导致系统性能受到一定影响

6. 枚举(最佳实践)

enum SingletonEnum {INSTANCE;public void doSomething() {System.out.println("Doing something...");}
}

优点

  • 天然线程安全
  • 天然防止反射攻击
  • 天然支持序列化/反序列化不破坏单例

Joshua Bloch 推荐写法(《Effective Java》作者)


其他案例:

  1. 某软件公司承接了一个服务器负载均衡(Load Balance)软件的开发工作,该软件运行在一台负载均衡服务器上,可以将并发访问和数据流量分发到服务器集群中的多台设备上进行并发处理,提高了系统的整体处理能力,缩短了响应时间。由于集群中的服务器需要动态删减,且客户端请求需要统一分发,因此需要确保负载均衡器的唯一性,只能有一个负载均衡器来负责服务器的管理和请求的分发,否则将会带来服务器状态的不一致以及请求分配冲突等问题。如何确保负载均衡器的唯一性是该软件成功的关键,试使用单例模式设计服务器负载均衡器。
    在这里插入图片描述

  2. 身份证号码:在现实生活中,居民身份证号码具有唯一性,同一个人不允许有多个身份证号码,第一次申请身份证时将给居民分配一个身份证号码,如果之后因为遗失等原因补办时,还是使用原来的身份证号码,不会产生新的号码。现使用单例模式模拟该场景。
    在这里插入图片描述

  3. 打印池:在操作系统中,打印池(Print Spooler)是一个用于管理打印任务的应用程序,通过打印池用户可以删除、中止或者改变打印任务的优先级,在一个系统中只允许运行一个打印池对象,如果重复创建打印池则抛出异常。现使用单例模式来模拟实现打印池的设计。
    在这里插入图片描述

六、优缺点分析

优点描述
节省资源只创建一次实例,避免重复创建销毁带来的性能开销
全局访问提供统一的访问入口,便于集中管理
控制状态一致性避免多个实例导致的数据不一致问题
其他允许可变数目的实例(多例类)
缺点描述
违反单一职责原则单例类通常承担了太多责任,不符合高内聚低耦合原则
不利于测试依赖全局状态,难以进行单元测试
隐藏依赖关系使用单例时不容易看出类之间的依赖关系
扩展困难如果将来需要支持多个实例,重构成本较高
其他由于自动垃圾回收机制,可能会导致共享的单例对象的状态丢失

七、最终小结

单例模式是 Java 开发中最常用的设计模式之一,它的核心思想是:

保证一个类只有一个实例,并提供全局访问入口。

作为一名 Java 开发工程师,掌握单例模式是非常有必要的,尤其是在开发工具类、配置管理器、缓存服务等组件时。

✅ 推荐使用方式总结:

写法是否推荐适用场景
枚举✅✅✅最佳选择,防反射、线程安全
静态内部类✅✅常规项目首选
DCL手动控制懒加载
饿汉式⚠️类加载即初始化,适合简单场景
懒汉式多线程下不安全,慎用

📌 一句话总结:

单例模式就像你家里的“总开关”,不管谁去按,都是控制同一个灯,确保系统的“唯一性”和“一致性”。

如果你正在构建一个需要全局统一管理的组件,不妨考虑使用单例模式。

部分内容由AI大模型生成,注意识别!

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

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

相关文章

vue3 el-table 行数据沾满格自动换行

在使用 Vue 3 结合 Element Plus 的 <el-table> 组件时&#xff0c;如果你希望当表格中的行数据文本过长时能够自动换行&#xff0c;而不是溢出到其他单元格或简单地截断&#xff0c;你可以通过以下几种方式来实现&#xff1a;方法 1&#xff1a;使用 CSS最简单的方法是通…

windows电脑远程win系统服务器上的wsl2

情况 我自己使用win11笔记本电脑&#xff0c;想要远程win11服务器上的wsl2 我这里只有服务器安装了wsl2&#xff0c;win11笔记本没有安装 因此下面提到的Ubuntu终端指的是win服务器上的wsl2终端 一定要区分是在哪里输入命令&#xff01;&#xff01; 安装SSH 在服务器上&#x…

神经辐射场 (NeRF):重构三维世界的AI新视角

神经辐射场 (NeRF)&#xff1a;重构三维世界的AI新视角 旧金山蜿蜒起伏的街道上&#xff0c;一辆装备12个摄像头的Waymo自动驾驶测试车缓缓驶过。它记录的280万张街景图像并未被简单地拼接成平面地图&#xff0c;而是被输入一个名为Block-NeRF的神经网络。数周后&#xff0c;一…

Kubernetes自动扩缩容方案对比与实践指南

Kubernetes自动扩缩容方案对比与实践指南 随着微服务架构和容器化的广泛采用&#xff0c;Kubernetes 自动扩缩容&#xff08;Autoscaling&#xff09;成为保障生产环境性能稳定与资源高效利用的关键技术。面对水平 Pod 扩缩容、垂直资源调整、集群节点扩缩容以及事件驱动扩缩容…

【CVPR2025】计算机视觉|SIREN: 元学习赋能!突破INR高分辨率图像分类难题

论文地址&#xff1a;https://arxiv.org/pdf/2503.18123v1 代码地址&#xff1a;https://github.com/SanderGielisse/MWT 关注UP CV缝合怪&#xff0c;分享最计算机视觉新即插即用模块&#xff0c;并提供配套的论文资料与代码。 https://space.bilibili.com/473764881 摘要 …

牛客周赛 Round 99

赛时成绩如下&#xff1a;A. Round 99题目描述 对于给定的五位整数&#xff0c;检查其中是否含有数字 99&#xff1b;换句话说&#xff0c;检查是否存在相邻的两个数位&#xff0c;其值均为 。解题思路&#xff1a; 检查相邻的两个数字是否均为9#include <bits/stdc.h> u…

从0到1搭建个人技术博客:用GitHub Pages+Hexo实现

一、为什么要搭建个人技术博客&#xff1f; 在技术圈&#xff0c;拥有个人博客的好处不言而喻&#xff1a; 简历加分项&#xff1a;面试官更青睐有技术沉淀的候选人知识系统化&#xff1a;输出倒逼输入&#xff0c;加深技术理解人脉拓展&#xff1a;吸引同行关注&#xff0c;…

Ubuntu22.04 设置显示存在双屏却无法双屏显示

文章目录一、背景描述二、解决方法一、背景描述 回到工位后&#xff0c;发现昨天离开时还可正常显示的双屏&#xff0c;今早ubuntu22.04 的设置界面显示有双屏&#xff0c;但外接的显示屏无法正常显示。 首先&#xff0c;查看当前图像处理显卡是否为N卡&#xff0c;没错&#…

高亚科技签约奕源金属,助力打造高效智能化采购管理体系

深圳市奕源金属制品有限公司近日&#xff0c;国内企业管理软件服务商高亚科技与深圳市奕源金属制品有限公司&#xff08;以下简称“奕源金属”&#xff09;正式签约&#xff0c;双方将基于高亚科技自主研发的8Manage SRM采购管理系统&#xff0c;共同推动奕源金属采购管理的数字…

数据结构之map

map的基本介绍我们常常把map称之为映射&#xff0c;就是将一个元素&#xff08;通常称之为key键&#xff09;与一个相对应的值&#xff08;通常称之为value&#xff09;关联起来&#xff0c;比如说一个学生的名字&#xff08;key&#xff09;有与之对应的成绩&#xff08;value…

vue3 canvas 选择器 Canvas 增加页面性能

文章目录Vue3 选择器 Canvas 增加页面性能基于Vue3 Composition API和Canvas实现的交互式选择器&#xff0c;支持PC端和移动端的拖动选择、多选取消选择功能vue3组件封装html代码Vue3 选择器 Canvas 增加页面性能 基于Vue3 Composition API和Canvas实现的交互式选择器&#xf…

Python 实战:打造多文件批量重命名工具

引言在实际运维、测试、数据分析、开发流程中&#xff0c;我们经常会处理成百上千条命令操作&#xff0c;例如&#xff1a;各种脚本任务&#xff08;启动、备份、重启、日志查看&#xff09;数据处理流程&#xff08;爬取 → 清洗 → 统计 → 可视化&#xff09;配置自动化&…

设计模式笔记_结构型_代理模式

1. 代理模式介绍代理模式是一种结构型设计模式&#xff0c;它允许你提供一个代理对象来控制对另一个对象的访问。代理对象通常在客户端和目标对象之间起到中介作用&#xff0c;能够在不改变目标对象的前提下增加额外的功能操作&#xff0c;比如延迟初始化、访问控制、日志记录等…

C语言<数据结构-单链表>(收尾)

上篇博客我将基础的尾插、尾删、头插、头删逐一讲解了&#xff0c;这篇博客将对上篇博客进行收尾&#xff0c;讲一下指定位置操作增删以及查找这几个函数&#xff0c;其实大同小异&#xff1a;一.查找函数&#xff1a;查找函数其实就是一个简单的循环遍历&#xff0c;所以不加以…

十年架构心路:从单机到云原生的分布式系统演进史

十年架构心路&#xff1a;从单机到云原生的分布式系统演进史 这里写目录标题十年架构心路&#xff1a;从单机到云原生的分布式系统演进史一、技术生涯的起点&#xff1a;单体架构的黄金时代1.1 典型技术栈1.2 记忆深刻的故障二、分布式架构转型期2.1 服务化拆分实践2.2 分布式事…

使用docker搭建nginx

安装docker 和 docker compose验证docker版本配置docker目录配置代理&#xff0c;使docker能访问外网能否ping通最后直接拉入镜像即可docker pull nginx

Intel新CPU助攻:微软Copilot+将登陆台式电脑

微软的Copilot PC计划已经推出一年多&#xff0c;但目前仅支持平板电脑和笔记本电脑&#xff0c;以及少数迷你电脑。 随着Intel下一代桌面处理器——代号为“Arrow Lake Refresh”的推出&#xff0c;Copilot PC功能有望扩展到桌面计算机。 要支持Copilot PC的所有功能&#xff…

【Kubernetes】跨节点 Pod 网络不通排查案例

最近在部署一个集群环境的时候&#xff0c;发现集群中一个子节点与其他子节点不通&#xff0c;而 master 节点可与任何子节点互通&#xff0c;通过抓包排查后&#xff0c;发现是 Linux 路由决策导致的。因此&#xff0c;在此记录下来&#xff0c;希望对大家有所帮助。1、环境及…

【算法训练营Day11】二叉树part1

文章目录理论基础二叉树的递归遍历前序遍历中序遍历后序遍历总结二叉树的层序遍历基础层序遍历二叉树的右视图理论基础 二叉树在结构上的两个常用类型&#xff1a; 满二叉树完全二叉树 在功能应用上的比较常用的有&#xff1a; 二叉搜索树&#xff1a; 节点有权值、遵循”左…

Flutter 之 table_calendar 控件

1.库导入在pubspec.yaml文件中dev_dependencies:table_calendar: ^3.2.02. 代码编写TableCalendar(daysOfWeekHeight: 20,availableGestures: AvailableGestures.horizontalSwipe,firstDay: DateTime.now().subtract(const Duration(days: 365)),lastDay: DateTime.now(),cal…