【设计模式】单例模式详解及应用实例
单例模式(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系统中,通…...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
