【设计模式 01】单例模式

单例模式,是一种创建型设计模式,他的核心思想是保证一个类只有一个实例(即,在整个应用程序中,只存在该类的一个实例对象,而不是创建多个相同类型的对象),并提供一个全局访问点来访问这个实例(即,其他类只能通过一个,可以是静态方法,来获取到这个唯一实例)。

优势:因为只有一个实例,既避免了多次创建相同的对象,节省了系统资源。多个类,也就是模块之间可以通过单例实例来共享数据;同时方便我们站在全局的角度控制唯一实例的访问(即,可以严格的控制客户怎样访问它、何时访问他);此外,单例模式还允许只在需要时才进行实例化,即所谓的懒加载,以提高程序的性能。

实现一个单例设计模式需要满足以下的基本要求首先,任何外部代码不能够随意创建实例,也就意味着类的构造函数只能私有;其次,任何外部代码也不能够随意访问实例中的任何资源,也就意味着所有的静态实例变量须是私有的;最后,需要设置一个公有的静态方法,以便外部能够获取到实例的内部资源。

单例模式的实现方式有:懒汉式(只有在遇到请求实例时才会创建一个实例,并且如果已经创建过,就会返回已有的实例)、饿汉式(类加载时就已经完成了实例的创建,不管创建的实例在后面会不会使用,先创建再说)等。

在多线程环境下,由于饿汉式在程序启动阶段就完成实例的初始化,因此不存在多个线程同时尝试初始化实例的问题;但是懒汉式中多个线程同时访问 GetInstance() 方法,并且在同一时刻检测到实例没有被创建(只要线程切换足够频繁就有可能发生),就可能会同时创建实例,从而导致多个实例被创建,(好比你和小明都发现家里每米了,在你们没有相互通知的情况下,都会去超市买一袋米,这样就重复购买了,违背了单例模式)这种情况下我们可以采用一些同步机制,例如使用互斥锁来确保在任何时刻只有一个线程能够执行实例的创建。

以下是单例设计模式的基本写法,以Java代码为例

  • 饿汉式:
public class Singleton {private static final Singleton instance = new Singleton(); // 类加载时就被创建private Singleton() {// 私有构造方法,防止外部实例化}public static Singleton getInstance() {return instance;}
} 
  • 懒汉式 + 互斥锁:
public class Singleton {private static final Singleton instance;private Singleton() {// 私有构造方法,防止外部实例化}public static synchronized Singleton getInstance() {if (instance == null) {instance == new Singleton();}return instance;}
} 
  • 懒汉式 + 双重检查锁提高性能:
public class Singleton {private static final Singleton instance;private Singleton() {// 私有构造方法,防止外部实例化}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance == new Singleton();}}}return instance;}
} 

在Java中,关键字synchronized用于实现线程的同步。

首先,synchronized可以用来修饰方法,表示该方法在同一时间只能被一个线程访问。当一个线程访问该方法时,其他线程必须等待该线程执行完毕才能访问该方法。

其次,synchronized还可以用来修饰代码块。当多个线程需要访问共享资源时,可以使用synchronized来保证同一时间只有一个线程可以访问该资源。synchronized代码块使用一个对象作为锁,当一个线程进入synchronized代码块时,会尝试获取该对象的锁,如果锁被其他线程占用,则该线程被阻塞,直到锁被释放。

synchronized的作用是避免多个线程对共享资源的并发访问导致的数据不一致或者错误。通过使用synchronized,可以保证在同一时间只有一个线程对共享资源进行访问,从而保证了线程安全。

"类.class"是Java编程中的一种语法结构,用于获取某个类的Class对象。在Java中,每个类都对应一个Class对象,该对象包含了有关类的结构、字段、方法等信息,可以在程序运行时通过反射机制来访问和操作类的成员。

通过类名后面添加".class",可以获得该类的Class对象。例如,"String.class"返回String类的Class对象,"Integer.class"返回Integer类的Class对象。

使用Class对象可以进行一些操作,比如实例化对象、访问类的静态成员、获取类的父类和接口等。

请注意,类.class只能用于获取该类的Class对象,不能用于实例化这个类的对象。要实例化一个类的对象,可以使用Class对象中的newInstance()方法或者使用构造函数来创建对象。

总结一下,我们应当什么时候使用单例设计模式:

  1. 如果多个模块都需要共享某一种资源,例如一个全局的配置管理器来存储管理配置信息、管理数据库连接池信息等,可以使用单例设计模式。
  2. 如果创建对象本身就比较消耗资源,而且可能在整个程序中都不一定会使用,就可以使用单例模式中的懒加载;
  3. 有些场景中只需要一个实例就足以协调所有行为,创建多个实例没有必要甚至会导致不好的后果,例如管理应用程序中的缓存、管理线程池。

管理应用程序中的缓存只需要一个缓存实例的原因是为了保持数据的一致性和避免冲突。

当应用程序使用多个缓存实例时,可能会导致以下问题:

  1. 数据一致性:如果多个缓存实例各自独立管理数据,那么在不同实例中的数据可能会不一致。当更新或删除数据时,如果没有及时同步所有的缓存实例,可能导致数据的不一致性,从而引发潜在的问题。

  2. 资源浪费:每个缓存实例都需要占用内存和其他资源,如果使用多个缓存实例,会造成资源的浪费。而只使用一个缓存实例可以更有效地利用资源。

  3. 缓存冲突:多个缓存实例可能会导致相同的数据被同时缓存在不同的实例中,从而造成缓存冲突。如果多个实例同时读写相同的数据,可能会引发并发问题,影响应用程序的性能和正确性。

通过只使用一个缓存实例,可以确保数据的一致性,并最大程度地节省资源。可以使用单例模式来创建和管理缓存实例,确保应用程序中只存在一个缓存对象。这样可以简化缓存管理的操作,提高系统的可靠性和性能。

【设计模式专题之单例模式】1.小明的购物车

 CPP版本:

#include <iostream>
#include <vector>
#include <map>using namespace std;class ShoppingCartManager {
public:// 获取购物车实例static ShoppingCartManager& getInstance() {static ShoppingCartManager instance;return instance;}// 添加商品到购物车void addToCart(const string& itemName, int quantity) {if (cart.find(itemName) == cart.end()) {order.push_back(itemName);}cart[itemName] += quantity;}// 查看购物车void viewCart() const {for (const auto& itemName : order) {cout << itemName << " " << cart.at(itemName) << endl; // 不能使用cart[itemName],因为处在一个const方法,不能有修改变量值的格式出现。}}private:// 私有构造函数ShoppingCartManager() {}// 购物车存储商品和数量的映射map<string, int> cart;// 记录加入购物车的顺序vector<string> order;
};int main() {string itemName;int quantity;while (cin >> itemName >> quantity) {// 获取购物车实例并添加商品ShoppingCartManager& cart = ShoppingCartManager::getInstance();cart.addToCart(itemName, quantity);}// 输出购物车内容const ShoppingCartManager& cart = ShoppingCartManager::getInstance();cart.viewCart();return 0;
}

在C++中,static关键字可以有多种作用

  1. 静态变量(Static Variables):在函数内使用static关键字,可以创建静态变量。静态变量在函数调用结束后仍然存在,并且在下一次调用函数时保持其值不变。这使得静态变量在需要记住上一次函数调用结果或在多次调用之间共享数据时非常有用。

  2. 静态成员变量(Static Member Variables):在类内部使用static关键字,可以创建静态成员变量。静态成员变量属于类本身而不是类的实例,因此在不创建类的对象时也可以访问和修改它们。静态成员变量在类的所有实例之间共享数据。

  3. 静态函数(Static Functions):在类内部使用static关键字,可以创建静态函数。静态函数不依赖于类的实例,因此可以直接通过类名调用,无需创建类的对象。静态函数主要用于处理和类本身相关的操作,而不是与类的实例数据交互。

  4. 静态类(Static Classes):在C++中,可以将类声明为static类。静态类的成员函数和成员变量都必须是静态的,而且无法创建静态类的对象。静态类主要用于实现一些全局可访问的、不需要创建对象的功能,类似于命名空间的作用。

总的来说,C++中的static关键字可以用于创建静态变量、静态成员变量、静态函数以及静态类,它们都具有特定的作用和用途。

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

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

相关文章

vite项目修改node_modules

问题详情 在使用某个依赖的时候遇到了bug&#xff0c;提交issue后不想一直等待到作者更新版本&#xff0c;所以寻求临时自己解决 问题解决 在node_modules里找到需要修改的依赖&#xff0c;修改想要修改的代码 修改后记得保存 然后在node_modules里找到.vite文件夹&#x…

阿里云Linux系统MySQL8忘记密码修改密码

相关版本 操作系统&#xff1a;Alibaba Cloud Linux 3.2104 LTS 64位MySQL&#xff1a;mysql Ver 8.0.34 for Linux on x86_64 (Source distribution) MySQL版本可通过下方命令查询 mysql --version一、修改my.cnf文件 文件位置&#xff1a;etc/my.cnf进入远程连接后可以打…

MQTT控制报文介绍(2)

一、CONNECT – 连接 服务端 客户端到服务端的网络连接建立后&#xff0c;客户端发送给服务端的第一个报文 必须是 CONNECT 报文。在一个网络连接上&#xff0c;客户端只能发送一次 CONNECT 报文。服务端 必须将客户端发送的第二个 CONNECT报文当作协议违规处理并断开客户端的…

项目中spring security与jwt.腾讯面试分享

写这篇文章是为了记录我面试pcg时平时没有留意或者钻研的地方。 面试是根据项目问的问题&#xff1a; 为什么采用jwt存储token&#xff1f; 我的项目是微服务项目&#xff0c;里面部署了资源服务和认证服务&#xff0c;这里选择jwt作为token一方面是可以存储用户的信息&#…

Ultimaker Cura使用(具体材料具体分析!)

参考视频&#xff1a;Cura学习视频 1 软件下载地址 Ultimaker官网- 专业便捷的3D打印品牌 2 软件设置 &#xff08;1&#xff09;中文设置&#xff1a; 偏好设置->language->简体中文->关掉界面&#xff0c;重启 &#xff08;2&#xff09;添加打印机 Custom FF…

二叉树前序遍历函数 代码图解(先序遍历 深度优先遍历)

void PreOrder(BiTree p)//只是遍历 即只是读&#xff0c;不会改变树根 {//这个p的类型是 树的结构体 不是之前的p指针if(p!NULL){printf("%c", p->c);PreOrder(p->lchild);//函数嵌套 打印左子树PreOrder(p->rchild);//函数嵌套 打印右子树} } 同理可证 中…

Mysql运维篇(七) 部署MHA--完结

一路走来&#xff0c;所有遇到的人&#xff0c;帮助过我的、伤害过我的都是朋友&#xff0c;没有一个是敌人。如有侵权&#xff0c;请留言&#xff0c;我及时删除&#xff01; 一、MHA软件构成 Manager工具包主要包括以下几个工具&#xff1a; masterha_manger 启…

手撕指针第一页

1. 理解内存和地址 1.1 内存 内存&#xff0c;顾名思义就是电脑用来存储数据的&#xff0c;当CPU&#xff08;中央处理器&#xff09;在工作时&#xff0c;不仅需要从内存中拿取数据也需要将数据放入内存当中&#xff0c;当把内存引入到现实当中&#xff0c;就像学校里面的宿…

Leetcode : 506. 相对名次

思路 &#xff1a; 遍历计算每个元素比它大的元素个数&#xff0c;并判断做出对应结果标签&#xff1b; #include <iostream> #include <vector>using namespace std;class Solution { public:vector<string> findRelativeRanks(vector<int>& scor…

DataGrip(IDEA 内置)连接 SQL Server

原文&#xff1a;https://blog.iyatt.com/?p14265 测试环境&#xff1a; IDEA 2023.1SQL Server 2022 首先打开 SQL Server 配置管理工具 启用 TCP/IP 打开 Windows 服务管理 在服务列表中找到 SQL Server&#xff08;MSSQLSERVER&#xff09;&#xff0c;右键重新启…

开发一套pacs系统需要考虑哪些因素?

PACS全称Picture Archivingand Communication Systems。它是应用在医院影像科室的系统&#xff0c;主要的任务就是把日常产生的各种医学影像&#xff08;包括核磁&#xff0c;CT&#xff0c;超声&#xff0c;X光机&#xff0c;红外仪、显微仪等设备产生的图像&#xff09;通过各…

Unity 轮转图, 惯性, 自动回正, 点击选择

简单的实现 2D 以及 3D 的轮转图, 类似于 Web 中无限循环的轮播图那样. 文中所有代码均已同步至 github.com/SlimeNull/UnityTests 3D 轮转图: Assets/Scripts/Scenes/CarouselTestScene/Carousel.cs2D 轮转图: Assets/Scripts/Scenes/CarouselTestScene/UICarousel.cs 主要逻…

【Spring高级】第2讲:容器实现类

目录 BeanFactory实现BeanDefinition后置处理器单例bean创建后置处理器顺序总结 ApplicationContext实现ClassPathXmlApplicationContextFileSystemXmlApplicationContextAnnotationConfigApplicationContextAnnotationConfigServletWebServerApplicationContext BeanFactory实…

springboot3.x 以上,官方不建议使用spring.factories

springboot2.7.x 以上,官方不建议使用spring.factories 最近公司项目升级.需要将springcloud/springboot版本升级到2.7.x以上,再升级的过程中遇到了太多的问题.总结在了如下文章中: springboot艰难版本升级之路!! springboot 2.3.x版本升级到2.7.x版本 这篇文章就重点是梳理一…

如何让多个视频同时转GIF 2024全新款 高清无损转换

大家是否经常会遇到这样的问题&#xff0c;看到一些有趣的短视频片段&#xff0c;但却不知道如何将它们转换成GIF动图&#xff1f;今天&#xff0c;小编就给大家分享一个简单教程&#xff0c;教你如何批量将喜欢的短视频转换成GIF动图&#xff0c;让我们一起来学习吧&#xff0…

linux安装ngnix

一、将nginx-1.20.1.tar.gz上传至linux服务器目录下 二、将nginx安装包解压到/usr/local目录下 tar -zxvf /home/local/nginx-1.20.1.tar.gz -C /usr/local/三、预先安装依赖 yum -y install pcre-devel yum -y install openssl openssl-devel yum -y install gcc gcc-c auto…

【自然语言处理】【大模型】BitNet:用1-bit Transformer训练LLM

BitNet&#xff1a;用1-bit Transformer训练LLM 《BitNet: Scaling 1-bit Transformers for Large Language Models》 论文地址&#xff1a;https://arxiv.org/pdf/2310.11453.pdf 相关博客 【自然语言处理】【大模型】BitNet&#xff1a;用1-bit Transformer训练LLM 【自然语言…

Vue3.2 + vue/cli-service 打包 chunk-vendors.js 文件过大导致页面加载缓慢解决方案

chunk-vendors.js 是/node_modules 目录下的所有模块打包成的包&#xff0c; 但是这包太大导致页面加载很慢&#xff08;我的都要3-4秒了&#xff09;&#xff0c; 这个时候就会出现白屏的情况 解决方案 1、compression-webpack-plugin 插件解决方案 1&#xff09;、安装 npm …

解决vue项目本地开发完成后部署到服务器后报404的问题

一、如何部署 前后端分离开发模式下&#xff0c;前后端是独立布署的&#xff0c;前端只需要将最后的构建物上传至目标服务器的web容器指定的静态目录下即可 我们知道vue项目在构建后&#xff0c;是生成一系列的静态文件 常规布署我们只需要将这个目录上传至目标服务器即可 /…

redis进阶(一)

文章目录 前言一、Redis中的对象的结构体如下&#xff1a;二、压缩链表三、跳跃表 前言 Redis是一种key/value型数据库&#xff0c;其中&#xff0c;每个key和value都是使用对象表示的。 一、Redis中的对象的结构体如下&#xff1a; /** Redis 对象*/ typedef struct redisO…