当前位置: 首页 > news >正文

【设计模式】创建型模式之单例模式(饿汉式 懒汉式 Golang实现)

定义

一个类只允许创建一个对象或实例,而且自行实例化并向整个系统提供该实例,这个类就是一个单例类,它提供全局访问的方法。这种设计模式叫单例设计模式,简称单例模式。

单例模式的要点:

  1. 某个类只能有一个实例
  2. 必须自行创建该实例
  3. 必须自行向整个系统提供该实例
    在这里插入图片描述
    时序图:
    在这里插入图片描述

用处

从业务概念上来看,有些数据在系统中只应该保留一份,就比较适合设计为单例类。比如,系统的配置信息。

使用场景:

  • 系统只需要一个实例对象,比如唯一的序列号生成器(业务方面),或是考虑到资源消耗太大而只允许创建一个对象
  • 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点外,不能通过其他途径访问该实例

优缺点

优点:

  • 提供了对唯一实例的受控访问
  • 因为在系统的内存里只存在一个对象,所以可以节约系统资源,尤其是一些需要频繁创建和销毁的对象
  • 允许可变数目的实例,基于单例模式进行扩展

缺点:

  • 没有抽象层,很难扩展
  • 职责过重,在一定程度上违背了“单一职责原则”。因为单例类既充当了工厂角色,提供了工厂方法,同时又充当了产品角色,包含一些业务方法,将产品的创建和产品的本身的功能融合到一起。

单例模式的唯一性

  1. 进程间唯一:默认单例模式的唯一性就是基于进程的唯一性。因为编写的代码成为可执行文件后,当运行该可执行文件时,操作系统会启动一个进程,将该可执行文件从磁盘加载到自己的进程地址空间,该进程依次执行文件中的代码,比如代码里有一个创建student对象的语句,进程就会在地址空间里创建一个student对象。如果在一个进程中创建另一个进程,操作系统会给新进程分配新的地址空间,而且将旧地址空间的内容拷贝一份,包括代码和数据,这样新进程里有且只有一个student对象,旧进程里也有且只有一个student,但是这两个对象并不是同一个对象。
  2. 线程间唯一:通过获取线程id来实现。但是在golang里主要使用协程,而且协程的id并不会暴露出来。
  3. 集群环境间唯一(多进程):通过外部共享存储的锁进行,如文件。将单例对象序列化后存储到外部共享存储区里(比如文件),进程在使用该单例对象的时候,需要对该单例对象加锁,避免其他进程再获取,然后将该对象加载到内存里,反序列化为单例对象,使用完后还要从内存里删除,再存储回外部共享存储区,并释放锁。

如何实现

  • 构造函数是private访问权限
  • 考虑对象创建时的线程安全问题
  • 考虑是否支持延迟加载
  • 考虑getInstance的性能问题,比如是否有加锁等

实现方式

饿汉式

在类加载的时候实例就已经创建好了,实例的创建过程线程安全,不支持延迟加载

有两种实现方式,第一种是定义全局变量的时候创建实例,第二种是采用包的init函数创建实例

注意这里的Singleton类型也要是大写字母开头的,因为GetInstance方法是大写字母开头,表明包外可访问,那么该方法的返回值也需要包外可访问。

package singleton// 单例模式 饿汉式实现
type Singleton struct{}var singleton *Singleton//1.全局变量的实现方式
//var singleton1 = &Singleton{}
//2. 包的init函数实现方式
func init() {singleton = &Singleton{}
}func GetInstance() *Singleton {return singleton
}

懒汉式

在获取实例的时候再去创建,实例创建过程需要加锁,支持延迟加载,不支持高并发

不加锁

只是对懒汉式创建的一个理解,在GetInstnce方法里判断singleton是否为空,为空的话就去创建一个实例,否则直接返回该实例。

存在线程安全问题,高并发的时候会创建多个对象,不推荐使用。

package singleton// 单例模式 懒汉式实现 不加锁
type Singleton struct{}var singleton *Singletonfunc GetInstance() *Singleton {if singleton == nil {singleton = &Singleton{}}return singleton
}

给方法加锁

GetInstance整个方法进行加锁,确保并发安全,但是每一个对象创建的时候都需要进行加锁解锁,效率低

package singletonimport "sync"// 单例模式 懒汉式实现 方法锁
type Singleton struct{}var singleton *Singleton
var mu sync.Mutexfunc GetInstance() *Singleton {mu.Lock()defer mu.Unlock()if singleton == nil {singleton = &Singleton{}}return singleton
}

双重检测

在懒汉式的基础上,将方法的锁改为类级别的锁,相对于懒汉式的粒度更小,不用每次都去获取锁

借助sync.Once确保只创建一次

package singletonimport "sync"// 单例模式 懒汉式实现 双重检测
type LazySingleton struct{}var lazySingleton *LazySingleton
var once = &sync.Once{}func GetLazyInstance() *LazySingleton {if lazySingleton == nil {once.Do(func() {lazySingleton = &LazySingleton{}})}return lazySingleton
}

静态内部类

java的静态内部类,线程安全,延迟加载

枚举

java的枚举特性

测试性能

测试饿汉式的init实现方法和懒汉式的sync.Once实现方法

package singletonimport "testing"func BenchmarkGetInstanceParallel(b *testing.B) {b.RunParallel(func(pb *testing.PB) {for pb.Next() {if GetInstance() != GetInstance() {b.Errorf("test fail")}}})
}func BenchmarkGetLazyInstanceParallel(b *testing.B) {b.RunParallel(func(pb *testing.PB) {for pb.Next() {if GetLazyInstance() != GetLazyInstance() {b.Errorf("test fail")}}})
}

在对应的目录下执行:

go test -bench='Parallel$' -benchmem .

在这里插入图片描述
可以看出饿汉式的性能更好一点

参考链接
图解设计模式
Go设计模式
Golang单例模式

相关文章:

【设计模式】创建型模式之单例模式(饿汉式 懒汉式 Golang实现)

定义 一个类只允许创建一个对象或实例,而且自行实例化并向整个系统提供该实例,这个类就是一个单例类,它提供全局访问的方法。这种设计模式叫单例设计模式,简称单例模式。 单例模式的要点: 某个类只能有一个实例必须…...

使用 Docker Compose 来编排部署LMTNR项目

使用 Docker Compose 来部署一个包含 Linux、MySQL、Tomcat、Nginx 和 Redis 的完整项目的例子。假设我们要部署一个简单的 Java Web 应用,并且使用 Nginx 作为反向代理服务器。 项目目录结构 首先需要确保 Docker 和docker-compose已经安装并正在运行。docker --v…...

创建HTTPS网站

每天,我们都会听到网络上发生身份盗窃和数据侵权的案例,这导致用户对自己访问的网站更加怀疑。他们开始更加了解自己将个人信息放在哪里以及信任哪些类型的网站。了解如何使网站使用HTTPS变得比以往任何时候都更加重要。 解读缩略词:HTTP与HT…...

以3D数字人AI产品赋能教育培训人才发展,魔珐科技亮相AI+教育创新与人才发展大会

11月20日,北京中关村国际创新中心迎来了“AI教育创新与人才发展大会暨首届北京数字人才发展大会”的盛大启幕。此次大会汇聚了培训、教育、科技、人才领域的专家学者、行业领袖及企业代表,共同探讨人工智能技术在教育培训领域的革新应用与数字人才培养体…...

springboot配置https,并使用wss

学习链接 springboot如何将http转https SpringBoot配置HTTPS及开发调试 Tomcat8.5配置https和SpringBoot配置https 可借鉴的参考: springboot如何配置ssl支持httpsSpringBoot配置HTTPS及开发调试的操作方法springboot实现的https单向认证和双向认证(java生成证…...

Qt SQL模块概述

Qt SQL支持的数据库 要在项目中使用 Qt SQL 模块&#xff0c;需要在项目配置文件中添加下面一条设置语句&#xff1a; Qt sql在头文件或源文件中使用 Qt SQL 模块中的类&#xff0c;可以使用包含语句&#xff1a; #include <QtSql>这样会将某个 Qt SQL 模块中的所有类…...

JavaWeb后端开发知识储备2

目录 1.HttpClient 2.微信小程序开发 3.Spring Cache 4.Spring Task 4.1cron表达式 4.2入门案例 5.WebSocket协议 1.HttpClient 简单来说&#xff0c;HttpClient可以通过编码的方式在Java中发送Http请求 2.微信小程序开发 微信小程序的开发本质上是前端开发&#xff0…...

RabbitMQ原理架构解析:消息传递的核心机制

文章目录 一、RabbitMQ简介1.1、概述1.2、特性 二、RabbitMQ原理架构三、RabbitMQ应用场景3.1、简单模式3.2、工作模式3.3、发布订阅3.4、路由模式3.5 主题订阅模式 四、同类中间件对比五、RabbitMQ部署5.1、单机部署5.2、集群部署&#xff08;镜像模式&#xff09;5.3、K8s部署…...

redmi 12c 刷机

刷机历程 一个多月前网购了redmi 12c这款手机, 价格只有550,用来搞机再适合不过了, 拆快递后就开始倒腾,网上有人说需要等7天才能解锁,我绑定了账号过了几天又忍不住倒腾,最后发现这块手机不用等7天解锁成功了,开始我为了获取root权限, 刷入了很火的magisk,但是某一天仍然发现/…...

四、Python —— 列表

文章目录 一、列表的初始化1.1、直接初始化1.2、通过 append 函数初始化1.3、 通过 for 语句初始化列表长度和每个位置的数值 二、访问列表元素2.1、越界的含义 三、 使用循环语句遍历列表3.1、通过下标遍历3.2、通过 for...in... 直接遍历 四、列表的切片操作五、列表的复制六…...

Paper -- 建筑高度估计 -- 基于街景图像和深度学习的城区建筑高度计算

基本信息 论文题目: Building height calculation for an urban area based on street view images and deep learning 中文题目: 基于街景图像和深度学习的城区建筑高度计算 作者及单位: – Zhen Xu Furong Zhang Yingying Wu Yajun Yang Yuan Wu – 北京科技大学城市与安全研…...

机器学习周志华学习笔记-第6章<支持向量机>

机器学习周志华学习笔记-第6章<支持向量机> 卷王&#xff0c;请看目录 6支持向量机6.1 函数间隔与几何间隔6.1.1 函数间隔6.1.2 几何间隔 6.2 最大间隔与支持向量6.3 对偶问题6.4 核函数6.5 软间隔支持向量机6.6 支持向量机6.7核方法 6支持向量机 支持向量机是一种经典…...

第三届航空航天与控制工程国际 (ICoACE 2024)

重要信息 会议官网&#xff1a;www.icoace.com 线下召开&#xff1a;2024年11月29日-12月1日 会议地点&#xff1a;陕西西安理工大学金花校区 &#xff08;西安市金花南路5号&#xff09; 大会简介 2024年第三届航空航天与控制工程国际学术会议&#xff08;ICoACE 2024&a…...

【大数据技术基础】 课程 第8章 数据仓库Hive的安装和使用 大数据基础编程、实验和案例教程(第2版)

第8章 数据仓库Hive的安装和使用 8.1 Hive的安装 8.1.1 下载安装文件 访问Hive官网&#xff08;http://www.apache.org/dyn/closer.cgi/hive/&#xff09;下载安装文件apache-hive-3.1.2-bin.tar.gz 下载完安装文件以后&#xff0c;需要对文件进行解压。按照Linux系统使用的…...

BERT 详解

BERT简介 BERT&#xff08;Bidirectional Encoder Representations from Transformers&#xff09;是由 Google 在 2018 年提出的一种预训练语言模型。BERT 在自然语言处理&#xff08;NLP&#xff09;领域取得了重大突破&#xff0c;因为它能够有效地捕捉文本的上下文信息&am…...

使用 MySQL 的 REPLACE() 函数轻松替换表中字段

前言 在数据库操作中&#xff0c;经常需要对存储的数据进行一些处理和修改&#xff0c;替换字段中的部分信息。MySQL 提供了多种字符串函数来帮助开发者完成这些任务。其中一个非常实用的函数就是 REPLACE()。 REPLACE() 函数简介 REPLACE() 函数用于在字符串中查找指定的子…...

Http 响应协议

HTTP的响应协议 响应数据格式 响应行 响应数据的第一行&#xff0c;包括协议、状态码、描述 响应头 从响应数据格式的第二行开始&#xff0c;也是以key:value的格式 响应体 和响应头之间有一个空行&#xff0c;是响应数据格式的最后一部分&#xff0c;用于存放响应的数据 常见响…...

TCP/IP 协议:网络世界的基石(2/10)

一、引言 在当今数字化时代&#xff0c;互联网已经成为人们生活中不可或缺的一部分。而在互联网的背后&#xff0c;TCP/IP 协议扮演着至关重要的角色&#xff0c;堪称互联网的基石。 TCP/IP 协议是一组用于数据通信的协议集合&#xff0c;它的名字来源于其中最重要的两个协议…...

Lua--1.基础知识

Lua基础知识 变量简单的4种变量类型复杂的4种变量类型type函数 字符串操作长度获取--#多行打印字符串拼接别的类型转字符串-- tostring()字符串提供的公共方法 运算符算术运算符-- - * / % ^条件运算符-- > < > < ~(不等于 是 ~)逻辑运算符-- and or not位运算、…...

【GPT】力量训练的底层原理?

详细解读力量训练的每一个底层原理 力量训练之所以有效&#xff0c;是因为它利用了肌肉、神经系统和生物化学反应的基本机制。以下逐一详细解析&#xff0c;并解释相关概念。 1. 应力-恢复-适应理论 概念解析 应力&#xff08;Stress&#xff09;&#xff1a;指训练带来的负…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

NPOI Excel用OLE对象的形式插入文件附件以及插入图片

static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器

一、原理介绍 传统滑模观测器采用如下结构&#xff1a; 传统SMO中LPF会带来相位延迟和幅值衰减&#xff0c;并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF)&#xff0c;可以去除高次谐波&#xff0c;并且不用相位补偿就可以获得一个误差较小的转子位…...

MyBatis中关于缓存的理解

MyBatis缓存 MyBatis系统当中默认定义两级缓存&#xff1a;一级缓存、二级缓存 默认情况下&#xff0c;只有一级缓存开启&#xff08;sqlSession级别的缓存&#xff09;二级缓存需要手动开启配置&#xff0c;需要局域namespace级别的缓存 一级缓存&#xff08;本地缓存&#…...

LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)

在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...