【设计模式】单例模式详解及应用实例
单例模式(Singleton Pattern)
是一种创建型设计模式,保证一个类在整个程序的生命周期中只有一个实例,并提供一个全局访问点。单例模式广泛用于需要全局唯一实例的场景,比如数据库连接池、日志对象、线程池等。
单例模式的特点
- 唯一性:确保一个类只有一个实例。
- 延迟实例化:通常使用懒加载机制,即在第一次使用时才创建实例。
- 全局访问:提供一个全局访问点供外部获取该实例。
单例模式的实现方式
单例模式有多种实现方式,常见的有以下几种:
1. 懒汉式(Lazy Initialization)
懒汉式的单例模式是延迟初始化的,实例在第一次使用时才创建。这种方式的缺点是线程不安全。
public class SingletonLazy {private static SingletonLazy instance;// 私有化构造函数,防止外部实例化private SingletonLazy() {}// 获取单例对象的静态方法public static SingletonLazy getInstance() {if (instance == null) {instance = new SingletonLazy();}return instance;}
}
缺点: 懒汉式在多线程环境下可能会创建多个实例,因为线程可能会同时通过 if (instance == null)
条件。
2. 线程安全的懒汉式(Synchronized Method)
为了在多线程环境下保证实例的唯一性,可以使用 synchronized
关键字使方法同步。
public class SingletonLazyThreadSafe {private static SingletonLazyThreadSafe instance;private SingletonLazyThreadSafe() {}// 同步方法保证线程安全public static synchronized SingletonLazyThreadSafe getInstance() {if (instance == null) {instance = new SingletonLazyThreadSafe();}return instance;}
}
缺点: 虽然线程安全,但由于 synchronized
关键字的使用,每次调用 getInstance
都会产生一定的性能开销。
3. 双重检查锁定(Double-Checked Locking)
双重检查锁定在性能和线程安全之间做了折中。通过在实例初始化前后都进行检查,减少同步的开销。
public class SingletonDCL {// volatile 保证变量的可见性和有序性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. 静态内部类(Static Inner Class)
利用 Java 的类加载机制实现懒加载,静态内部类方式在类加载时不会立即实例化,而是在调用 getInstance()
时才加载内部类并创建实例。
public class SingletonStaticInnerClass {private SingletonStaticInnerClass() {}// 静态内部类持有 Singleton 的唯一实例private static class SingletonHolder {private static final SingletonStaticInnerClass INSTANCE = new SingletonStaticInnerClass();}public static SingletonStaticInnerClass getInstance() {return SingletonHolder.INSTANCE;}
}
优点: 线程安全,且没有性能开销,推荐使用。
5. 枚举(Enum Singleton)
使用枚举实现单例是一种比较优雅的方式,因为 Java 枚举本身是线程安全的,并且只能有一个实例。
public enum SingletonEnum {INSTANCE;public void someMethod() {// 业务逻辑}
}
优点: 实现简单,枚举保证了线程安全且防止了反序列化破坏单例。
单例模式使用场景
- 配置类:当一个类只需要一个实例来提供全局配置时,比如读取配置文件的类。
- 数据库连接池:只需要一个连接池对象来管理数据库连接。
- 日志类:应用程序中通常需要一个全局的日志管理类。
- 线程池:应用程序只需要一个线程池来管理线程。
单例模式的使用技巧
-
防止反射破坏单例: 通过私有化构造器的方式可以阻止外部类直接使用
new
创建实例,但通过反射可以访问私有构造器破坏单例。为了解决这个问题,可以在构造器内加一个判断:private Singleton() {if (instance != null) {throw new RuntimeException("单例模式被破坏");} }
-
防止序列化破坏单例: 如果单例类实现了
Serializable
接口,在反序列化时可能会创建新的实例。为了解决这个问题,可以在类中实现readResolve
方法:private Object readResolve() {return instance; }
-
线程安全优化: 双重检查锁定(DCL)方式在保证线程安全的前提下,提高了性能,是多线程环境下常用的实现方式。
-
枚举单例推荐: 使用枚举实现单例模式可以简化代码,保证线程安全,并且防止反射和序列化破坏单例,因此被认为是最推荐的方式。
单例模式的实际实例
假设我们需要一个日志管理器,该管理器只允许创建一个实例,并能通过全局访问点进行日志记录。
public class LoggerSingleton {private static LoggerSingleton instance;private LoggerSingleton() {}// 双重检查锁定获取单例实例public static LoggerSingleton getInstance() {if (instance == null) {synchronized (LoggerSingleton.class) {if (instance == null) {instance = new LoggerSingleton();}}}return instance;}public void log(String message) {System.out.println("Log: " + message);}
}public class Main {public static void main(String[] args) {LoggerSingleton logger = LoggerSingleton.getInstance();logger.log("This is a singleton logger.");}
}
总结
- 单例模式提供了确保类实例唯一的有效方案,适用于全局共享资源。
- 常见实现方式包括懒汉式、双重检查锁定和静态内部类等。
- 推荐使用枚举实现单例,因为它天然防止了反射和序列化破坏单例的风险。
相关文章:
【设计模式】单例模式详解及应用实例
单例模式(Singleton Pattern)是一种创建型设计模式,保证一个类在整个程序的生命周期中只有一个实例,并提供一个全局访问点。单例模式广泛用于需要全局唯一实例的场景,比如数据库连接池、日志对象、线程池等。 单例模式…...

学习图解算法 使用C语言
图解算法 使用C语言 也就是通过C语言实现各种算法 链接:百度云盘 提取码:1001...
基于Netty实现TCP客户端:封装断线重连、连接保持
文章目录 引言I 基于Netty实现TCP客户端基于 Netty 创建客户端 时序图封装思路NettyClient 封装II 客户端的断线重连本质使用过程中断线重连重试策略III 心跳机制心跳检测处理器心跳机制实现逻辑IV 同步等待消息返回V 工具ForkJoinPoolByteConvertUtilsee also处理假死把handle…...

基于形状记忆聚合物的折纸超结构
公众号端文章: 基于SMP的折纸超结构https://mp.weixin.qq.com/s?__bizMzkwMjc0MTE3Mw&mid2247484016&idx4&sn16f8d4aaaff76d776cec19bc0adbdd3b&chksmc0a1afaaf7d626bc0457d9cc4ba1b38424c2aad71ffec548715e47f5611cf00f10d5a511f3b3#rd 折…...

前端用html写excel文件直接打开
源码 <html xmlns:o"urn:schemas-microsoft-com:office:office" xmlns:x"urn:schemas-microsoft-com:office:excel" xmlns"http://www.w3.org/TR/REC-html40"> <head><meta charset"UTF-8"><!--[if gte mso 9]&…...

FastText 和 Faiss 的初探了解
概览 大模型目前已经是如火如荼的程度,各个大厂都有推出面向大众的基础大模型,同时诸多行业也有在训练专有大模型,而大模型的发展由来却是经过多年从文本检索生成、深度学习、自然语言处理,在Transformer架构出来后,才…...

微服务保护学习笔记(五)Sentinel授权规则、获取origin、自定义异常结果、规则持久化
文章目录 前言4 授权规则4.1 基本原理4.2 获取origin4.3 配置授权规则 5 自定义异常结果6 规则持久化 前言 微服务保护学习笔记(一)雪崩问题及解决方案、Sentinel介绍与安装 微服务保护学习笔记(二)簇点链路、流控操作、流控模式(关联、链路) 微服务保护学习笔记(三)流控效果(…...

YOLOv8目标检测模型——遥感小目标检测经验分享
小目标检测——YOLOV8 一、引言 背景介绍 (1)目标检测的重要性 目标检测在许多领域都具有极其重要的作用。在自动驾驶中,目标检测能够识别道路上的障碍物和行人,确保行车安全。在视频监控中,目标检测能够实时发现异…...

构建响应式 Web 应用:Vue.js 基础指南
构建响应式 Web 应用:Vue.js 基础指南 一 . Vue 的介绍1.1 介绍1.2 好处1.3 特点 二 . Vue 的快速入门2.1 案例 1 : 快速搭建 Vue 的运行环境 , 在 div 视图中获取 Vue 中的数据2.2 案例 2 : 点击按钮执行 vue 中的函数输出 vue 中 data 的数据2.3 小结 三 . Vue 常…...

计算机毕业设计选题推荐-在线投票系统-Java/Python项目实战
✨作者主页:IT研究室✨ 个人简介:曾从事计算机专业培训教学,擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…...

【C/C++】程序的构建(编译)过程概述
🦄个人主页:小米里的大麦-CSDN博客 🎏所属专栏:C_小米里的大麦的博客-CSDN博客 🎁代码托管:C: 探索C编程精髓,打造高效代码仓库 (gitee.com) ⚙️操作环境:Visual Studio 2022 目录 一、前言 二、预处理(Preprocessi…...

ElasticSearch-2-核心语法集群高可用实战-Week2
ES批量操作 1.批量获取文档数据 这里多个文档是指,批量操作多个文档,搜索查询文档将在之后的章节讲解 批量获取文档数据是通过_mget的API来实现的 (1)在URL中不指定index和type 请求方式:GET 请求地址:_mget 功能说明 &#…...

STM的CAN通信学习
显性电平:0 隐性电平:1 一、帧结构 1.帧类型 1)数据帧:发送设备主动发送数据(广播式) 2)请求帧:接收设备主动请求数据(请求式) 2.帧结构 1ÿ…...

【高等数学学习记录】函数
【高等数学&学习记录】函数 从事测绘工作多年,深刻感受到基础知识的重要及自身在这方面的短板。 为此,打算重温测绘工作所需基础知识。练好基本功,为测绘工作赋能。 1 知识点 1.1 函数 设数集 D ⊂ R D\subset R D⊂R,称映射…...

【springboot过ingress后无法获取X-Forwarded-For头信息】
springboot过ingress后无法获取X-Forwarded-For头信息 一、现象结论修改步骤ingressspringboot 排查流程本文参考 一、现象 项目使用spring boot 2.7.18,有个新需求是校验X-Forwarded-For头的所有来源ip合法性,线上环境出现取不到X-Forwarded-For头的问…...

表格标记<table>
一.表格标记、 1table:表格标记 2.caption:表单标题标记 3.tr:表格行标记 4.td:表格中数据单元格标记 5.th:标题单元格 table标记是表格中最外层标记,tr表示表格中的行标记,一对<tr>表示表格中的一行,在<tr>中可…...

Rust练手项目,写个有趣的小工具定时从一言网获取一段有趣的话并推送通知
Rust练手项目,写个有趣的小工具 代码 继续练习Rust, 写个小工具定时从一言网获取一段有趣的话并提示,如下 练习以下Rust点 并发编程 Mutex, Arc指针使用HTTP请求Windows Gui 代码 Cargo.toml [package] name "funny_word" edition "20…...

【隐私计算】Paillier半同态加密算法
一、何为同态加密(HE)? HE是一种特殊的加密方法,它允许直接对加密数据执行计算,如加法和乘法,而计算过程不会泄露原文的任何信息。计算的结果仍然是加密的,拥有密钥的用户对处理过的密文数据进…...
判断数字的奇偶[中秋快乐~]
题目描述 给定一个整数 n,编写程序判断数字 n 是奇数还是偶数,是奇数则输出 “odd”,偶数则输出 “even”。 输入格式 一行,一个整数 n。 输出格式 一行,如果 n 是奇数则输出 “odd”; 如果 nn 是偶数则输出 “even”。 样例…...
文件操作及重定向详解
1、linux下一切皆文件: 在linux中,一切皆文件是一个重要的概念,用于描述linux操作系统中所有资源和设备都以文件的形式进行访问和处理。 这个概念可以理解为,无论是硬盘上的文件、网卡、设备、进程等,都被抽象为文件的形式存在。在linux系统中,通…...

Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...

dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...