【创建型设计模式】单例模式
【创建型设计模式】单例模式
这篇博客接下来几篇都将阐述设计模式相关内容。
接下来的顺序大概是:单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。
一、什么是单例模式
单例模式是一种创建型设计模式,它保证一个类仅有一个实例,并提供一个全局访问点。
核心思想:
- 限制类的实例化次数,确保全局只有一个实例。
- 提供统一访问该实例的方法。
Client 为客户端,Singleton 是单例类,通过调用 Singleton.getInstance() 来获取实例对象。
二、单例模式的 6 种方法
(1) 饿汉模式
public class Singleton {private static Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}
}
特点:
- 初始化时间: 类加载时即完成实例化。
- 访问效率: 调用
getInstance时无需等待,性能高。
优点:
- 基于类加载机制,天然线程安全。
- 实现简单,适用于单例对象较少被频繁初始化的场景。
缺点:
- 无法延迟加载,如果实例从未被使用,会浪费内存。
(2) 懒汉模式(线程不安全)
public class Singleton {private static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}
特点:
- 初始化时间: 第一次调用时才实例化。
- 访问效率: 多线程环境下存在问题,可能生成多个实例。
优点: 延迟加载,节省资源。
缺点: 线程不安全,多个线程同时调用可能创建多个实例,导致单例失效。
(3) 懒汉模式(线程安全)
public class Singleton {private static Singleton instance;private Singleton() {}public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}
特点:
- 线程安全性: 使用
synchronized关键字确保多线程下只生成一个实例。
优点: 在多线程环境中保证安全。
缺点: 同步锁导致性能下降,每次调用 getInstance 都需排队,影响效率。
(4) 双重检查模式(DCL)
public class Singleton {// 1. 声明 volatile 修饰的静态实例变量private static volatile Singleton instance;// 2. 私有化构造方法,防止外部直接实例化private Singleton() {}// 3. 提供对外获取实例的静态方法public static Singleton getInstance() {// 第一次检查:避免不必要的同步if (instance == null) {synchronized (Singleton.class) { // 加锁// 第二次检查:确保实例未被其他线程创建if (instance == null) {instance = new Singleton();}}}return instance;}
}
特点:
- 性能优化: 减少同步开销。
- 线程安全: 使用
volatile避免指令重排序,确保多线程环境下正确创建实例。
优点: 资源利用率高,延迟初始化,线程安全,性能优于懒汉模式(线程安全版)。
缺点: 实现复杂,某些情况下可能出现 DCL 失效问题(如旧版 JVM)。
DCL 模式的核心思想
DCL 的核心是两次检查和同步锁的结合。
**第一次检查(
if (instance == null)):**在大多数情况下,实例已经被初始化,可以直接返回,不需要加锁。减少了不必要的同步,提高性能。**加锁(
synchronized):**在实例尚未初始化时,进入临界区,防止多个线程同时创建实例。**第二次检查(
if (instance == null)):**加锁后,再次检查实例是否为null,防止多个线程同时通过第一次检查,确保单例对象只被创建一次。**
volatile关键字:**确保instance的修改对所有线程立即可见,防止指令重排序导致未完全初始化的对象被其他线程访问。
为什么需要
volatile?问题:指令重排序
在没有
volatile修饰时,JVM 编译器和 CPU 可能对以下代码进行优化:instance = new Singleton();这一行代码可能被分解为以下三步:
- 为对象分配内存。
- 初始化对象。
- 将对象引用赋值给
instance。但实际执行中,可能发生指令重排序:
- 为对象分配内存。
- 将对象引用赋值给
instance。- 初始化对象。
如果线程 A 在步骤 2 后被切换,线程 B 进入并访问了
instance,此时会得到一个未初始化的对象,导致程序行为不可预期。解决方法:
volatile关键字禁止指令重排序,确保对象初始化完成后才将引用赋值给instance。
(5) 静态内部类单例模式
public class Singleton {// 私有化构造方法,防止外部实例化private Singleton() {}// 静态内部类,持有单例实例private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}// 提供全局访问点,返回静态内部类中的单例实例public static Singleton getInstance() {return SingletonHolder.INSTANCE;}
}
特点:
- 延迟加载: 第一次调用
getInstance时才加载内部类,完成实例化。 - 线程安全: 内部类加载机制天然线程安全。
优点:
- 实现简单,避免同步开销。
- 兼具延迟加载和线程安全,推荐使用。
缺点: 无法控制实例销毁,适用单例生命周期较长的场景。
静态内部类的加载时机:
在 Java 中,类的加载是延迟的,只有在被真正使用时才会加载静态内部类。
主类被加载时,静态内部类不会被加载。
只有在调用静态内部类中的成员时,静态内部类才会被加载。
类加载的线程安全性:
JVM 在加载类时会自动保证线程安全。
静态变量
INSTANCE只会被初始化一次。
(6) 枚举单例
public enum Singleton {INSTANCE; // 枚举单例的唯一实例// 单例类的其他方法public void doSomething() {System.out.println("Singleton instance is working!");}
}
特点:
- 线程安全: 枚举的线程安全由 JVM 保证。
- 防反序列化破坏: 默认枚举实例不可反序列化。
优点:
- 实现简单,天生线程安全。
- 避免反序列化和反射破坏单例。
缺点:
- 不支持延迟加载。
- 某些场景下(如需要灵活实例化控制)不适用。
public class Test {public static void main(String[] args) {Singleton instance = Singleton.INSTANCE;instance.doSomething();}
}
为什么枚举单例是线程安全的?
**JVM 保证:**枚举类型在类加载时会由 JVM 初始化,类加载过程是线程安全的。
**枚举的单一实例特性:**枚举中的每个实例在加载时被自动创建,并且不可被外部修改。
三、单例实现对比
| 实现方式 | 是否线程安全 | 是否延迟加载 | 性能 | 复杂度 |
|---|---|---|---|---|
| 饿汉模式 | 是 | 否 | 高 | 简单 |
| 懒汉模式(不安全) | 否 | 是 | 高 | 简单 |
| 懒汉模式(同步) | 是 | 是 | 低(频繁加锁) | 简单 |
| 双重检查模式(DCL) | 是 | 是 | 较高 | 中等 |
| 静态内部类模式 | 是 | 是 | 高 | 简单 |
| 枚举单例 | 是 | 否 | 高 | 简单 |
相关文章:
【创建型设计模式】单例模式
【创建型设计模式】单例模式 这篇博客接下来几篇都将阐述设计模式相关内容。 接下来的顺序大概是:单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。 一、什么是单例模式 单例模式是一种创建型设计模式,它保证一个类仅有一个实例&#…...
Charles抓包工具-笔记
摘要 概念: Charles是一款基于 HTTP 协议的代理服务器,通过成为电脑或者浏览器的代理,然后截取请求和请求结果来达到分析抓包的目的。 功能: Charles 是一个功能全面的抓包工具,适用于各种网络调试和优化场景。 它…...
Go语言使用 kafka-go 消费 Kafka 消息教程
Go语言使用 kafka-go 消费 Kafka 消息教程 在这篇教程中,我们将介绍如何使用 kafka-go 库来消费 Kafka 消息,并重点讲解 FetchMessage 和 ReadMessage 的区别,以及它们各自适用的场景。通过这篇教程,你将了解如何有效地使用 kafk…...
【论文笔记】Number it: Temporal Grounding Videos like Flipping Manga
🍎个人主页:小嗷犬的个人主页 🍊个人网站:小嗷犬的技术小站 🥭个人信条:为天地立心,为生民立命,为往圣继绝学,为万世开太平。 基本信息 标题: Number it: Temporal Grou…...
C语言菜鸟入门·关键字·int的用法
目录 1. int关键字 1.1 取值范围 1.2 符号类型 1.3 运算 1.3.1 加法运算() 1.3.2 减法运算(-) 1.3.3 乘法运算(*) 1.3.4 除法运算(/) 1.3.5 取余运算(%) 1.3.6 自增()与自减(--) 1.3.7 位运算 2. 更多关键字 1. int关键字 int 是一个关键字࿰…...
基于企业微信客户端设计一个文件下载与预览系统
在企业内部沟通与协作中,文件分享和管理是不可或缺的一部分。企业微信(WeCom)作为一款广泛应用于企业的沟通工具,提供了丰富的API接口和功能,帮助企业进行高效的团队协作。然而,随着文件交换和协作的日益增…...
昇思MindSpore第七课---文本解码原理
1. 文本解码原理 文本解码是将模型的输出(通常是概率分布或词汇索引)转换为可读的自然语言文本的过程。在生成文本时,常见的解码方法包括贪心解码、束搜索(BeamSearch)、随机采样等。 2 实践 2.1 配置环境 安装mindn…...
C# 数据结构之【图】C#图
1. 图的概念 图是一种重要的数据结构,用于表示节点(顶点)之间的关系。图由一组顶点和连接这些顶点的边组成。图可以是有向的(边有方向)或无向的(边没有方向),可以是加权的ÿ…...
传输控制协议(TCP)和用户数据报协议(UDP)
一、传输控制协议(TCP) 传输控制协议(Transmission Control Protocol,TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由 IETF 的 RFC 793 定义。 它通过三次握手建立连接,确保数…...
【Python爬虫】Scrapy框架实战---百度首页热榜新闻
如何利用Scrapy框架实战提取百度首页热榜新闻的排名、标题和链接 一、安装Scrapy库 二、创建项目(以BaiduSpider为例) scrapy startproject BaiduSpider生成每个文件的功能: 二、 创建爬虫脚本(爬虫名:newsÿ…...
采用python3.12 +django5.1 结合 RabbitMQ 和发送邮件功能,实现一个简单的告警系统 前后端分离 vue-element
一、开发环境搭建和配置 #mac环境 brew install python3.12 python3.12 --version python3.12 -m pip install --upgrade pip python3.12 -m pip install Django5.1 python3.12 -m django --version #用于检索系统信息和进程管理 python3.12 -m pip install psutil #集成 pika…...
Qt 实现网络数据报文大小端数据的收发
1.大小端数据简介 大小端(Endianness)是计算机体系结构的一个术语,它描述了多字节数据在内存中的存储顺序。以下是大小端的定义和它们的特点: 大端(Big-Endian) 在大端模式中,一个字的最高有效…...
[译]Elasticsearch Sequence ID实现思路及用途
原文地址:https://www.elastic.co/blog/elasticsearch-sequence-ids-6-0 如果 几年前,在Elastic,我们问自己一个"如果"问题,我们知道这将带来有趣的见解: "如果我们在Elasticsearch中对索引操作进行全面排序会怎样…...
Java基于SpringBoot+Vue的藏区特产销售平台
博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…...
12-表的约束
知识背景 表的约束,就是在表中的数据上加上约束,也被称为数据完整性约束。数据完整性约束的目的是为了不被规定的、不符合规范的数据进入数据库 在录入数据库或数据发生变化时,DBMS(数据库管理系统)会按照一定的约束条件对数据进行监测&…...
【人工智能】深度学习入门:用TensorFlow实现多层感知器(MLP)模型
《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 多层感知器(MLP)是一种基础的神经网络结构,广泛应用于分类和回归任务。作为深度学习的重要组成部分,理解并实现MLP是学习更复杂神经网络模型的基础。本文将介绍多层感知器的核心概念、数学原理,并使用…...
【Go】-go中的锁机制
目录 一、锁的基础知识 1. 互斥量/互斥锁 2. CAS(compare and swap) 3. 自旋锁 4. 读写锁 5. 乐观锁 & 悲观锁 6. 死锁 二、go中锁机制 1. Mutex-互斥锁 2. RWMutex-读写锁 2.1 RWMutex流程概览 2.2 写锁饥饿问题 2.3. golang的读写锁源…...
c ++零基础可视化——vector
c 零基础可视化——vector 初始化 vector<int> v0(5); // 0 0 0 0 0 vector<int> v1(5, 1); // 1 1 1 1 1 vector<int> v2{1, 2, 3} // 1 2 3 vector<int> v3(v1); // 1 1 1 1 1 vector<vector<int>> v4(2, vect…...
Centos 7 安装 Docker 最新版本
文章目录 一、卸载旧版本二、安装最新版本docker三、问题解决3.1 启动docker报错3.2 启动容器报错 一、卸载旧版本 #如果之前安装过旧版本的Docker,可以使用下面命令卸载 yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest …...
构建高效在线教育:SpringBoot课程管理系统
1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及,互联网成为人们查找信息的重要场所,二十一世纪是信息的时代,所以信息的管理显得特别重要。因此,使用计算机来管理在线课程管理系统的相关信息成为必然。开发…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...
接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...
Ubuntu Cursor升级成v1.0
0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
