深入剖析Golang中单例模式
前言
虽说Golang并不是C++、Java这种传统的面向对象语言,而是偏向于面向接口编程的语言。但是Golang依旧有接口、结构体、组合等概念去模拟所谓面向对象中非常重要的设计模式。基于面向对象的模型去编写代码往往能编写成高内聚、低耦合、扩展性极强、难出bug的高质量代码结构。
而这个系列主要介绍比较常用的创造型、结构型、行为型设计模式以及Golang中的实现、案例…
什么是单例模式?
单例模式是一类经典且简单的设计模式
在单例模式下,我们的目的是声明一个类并保证这个类只存在全局唯一的实例供外部反复使用.
而要点简要来讲就是:
1.该类在整个运行周期中仅能够被实例化一次
2.该类的实例化对象对外是不可见的,且必须自行提供一个公共的访问点供客户端去使用
3.该实例应被自行创建
那么符合以上标准那便是一个单例模式的使用
那么其实说到这里大家肯定就会想到在日常工程中,很多组件的实例其实就是用了单例模式来初始化的。比如Mysql中间件,我们就希望该DB类仅被初始化一次,并暴露一个全局的DB供应。又或者系统要求提供一个唯一的序列号生成器或资源管理器,或者需要考虑资源消耗太大而只允许创建一个对象。
饿汉模式与懒汉模式
而单例模式的实现又分为了两种,分别是饿汉模式与懒汉模式。
饿汉模式
顾名思义,饿汉就是说很饿,很饿怎么办?程序一运行,那么就将这个单例去初始化拿到实例不就不饿了么=0= ~
饿汉模式的Golang实现代码Demo
再回顾一下单例模式的标准
1.该类在整个运行周期中仅能够被实例化一次
2.该类的实例化对象对外是不可见的,且必须自行提供一个公共的访问点供客户端去使用
3.该实例应被自行创建
简单看一下饿汉式
//1、保证这个类非公有化,外界不能通过这个类直接创建一个对象
// 那么这个类就应该变得非公有访问 类名称首字母要小写
type singelton struct {}//2、但是还要有一个指针可以指向这个唯一对象,但是这个指针永远不能改变方向
// Golang中没有常指针概念,所以只能通过将这个指针私有化不让外部模块访问
var instance *singelton = new(singelton)//3、如果全部为私有化,那么外部模块将永远无法访问到这个类和对象,
// 所以需要对外提供一个方法来获取这个唯一实例对象
// 注意:这个方法是否可以定义为singelton的一个成员方法呢?
// 答案是不能,因为如果为成员方法就必须要先访问对象、再访问函数
// 但是类和对象目前都已经私有化,外界无法访问,所以这个方法一定是一个全局普通函数
func GetInstance() *singelton {return instance
}func (s *singelton) SomeThing() {fmt.Println("单例对象的某方法")
}func main() {s := GetInstance()s.SomeThing()
}
这就是饿汉式一个简单的demo,在程序进入main()前instance就已经被实例化了
懒汉模式
而与之对应的就是懒汉模式了。唯一不同之处就是懒汉模式并不会在一开始就去实例化该单例,而是在第一次使用到它的时候,才会将其初始化并返回。。这就引伸出了一个问题,我们如何让这个单例只在第一次被调用的时候而初始化?换言之怎么让该实例被初始化的业务代码只能被全局调用一次?
而这个问题对熟悉Golang的小伙伴并不是什么难事,因为Golang其实有提供sync.once这样一个接口来让某个逻辑只在这个程序中执行一次。
package mainimport ("fmt""sync"
)var once sync.Oncetype singelton struct {}var instance *singeltonfunc GetInstance() *singelton {once.Do(func(){instance = new(singelton)})return instance
}func (s *singelton) DoPrint() {fmt.Println("666")
}func main() {s := GetInstance()s.SomeThing()
}
当我们使用现成封装好的api时,我们应该有刨根问底的心态,知其然知其所以然。下面我们简单看看sync.once的底层代码是怎样的。
type Once struct {// 通过一个整型变量标识,once 保护的函数是否已经被执行过done uint32// 一把锁,在并发场景下保护临界资源 done 字段只能串行访问m Mutex
}
在 sync.Once 的定义类中 包含了两个核心字段:
- done:一个整型 uint32,用于标识用户传入的任务函数是否已经执行过了
- m:一把互斥锁 sync.Mutex,用于保护标识值 done ,避免因并发问题导致数据不一致(保证线程安全)
func (o *Once) Do(f func()) {// 锁外的第一次 check,读取 Once.done 的值if atomic.LoadUint32(&o.done) == 0 {o.doSlow(f)}
}func (o *Once) doSlow(f func()) {// 加锁o.m.Lock()defer o.m.Unlock()// double checkif o.done == 0 {// 任务执行完成后,将 Once.done 标识为 1defer atomic.StoreUint32(&o.done, 1)// 保证全局唯一一次执行用户注入的任务f()}
}
而Do就是让里面的代码能被只执行一次的核心代码块,代码很清晰易懂,我就不过多赘述,主要通过atomic进行原子性的对done这个状态量去变更,以及核查值是否变更过来判断该f函数是否被执行过。
总结
以上就是我对单例模式的讲解以及Go实现,顺便讲解了一下sync.once底层原理
相关文章:
深入剖析Golang中单例模式
前言 虽说Golang并不是C、Java这种传统的面向对象语言,而是偏向于面向接口编程的语言。但是Golang依旧有接口、结构体、组合等概念去模拟所谓面向对象中非常重要的设计模式。基于面向对象的模型去编写代码往往能编写成高内聚、低耦合、扩展性极强、难出bug的高质量…...
Java之SpringCloud Alibaba【八】【Spring Cloud微服务Gateway整合sentinel限流】
一、Gateway整合sentinel限流 网关作为内部系统外的一层屏障,对内起到-定的保护作用,限流便是其中之- - .网关层的限流可以简单地针对不同路由进行限流,也可针对业务的接口进行限流,或者根据接口的特征分组限流。 1、添加依赖 <dependency><groupId>c…...
深入解析 Redis 分布式锁原理
一、实现原理 1.1 基本原理 JDK 原生的锁可以让不同线程之间以互斥的方式来访问共享资源,但如果想要在不同进程之间以互斥的方式来访问共享资源,JDK 原生的锁就无能为力了。此时可以使用 Redis 来实现分布式锁。 Redis 实现分布式锁的核心命令如下&am…...
[unity]多脚本情况下update函数的执行顺序
序 有的时候,执行某些脚本时会有先后顺序的要求。unity是按什么顺序来执行脚本的?如何设置? 默认的执行顺序 官方文档里面有个很长的图: Unity - Manual: Order of execution for event functions (unity3d.com) 根据文档&…...
Maven中<scope>中等级的区别
标签指定了依赖项的级别吗,默认是compile (编译)。意味着依赖项将会在编译时和运行时都被包含在项目中 <scope> 标签指定了依赖项的级别为 import 。除了 import 级别,Maven还支持以下几种级别: compile &#x…...
小明和完美序列(HashMap、Map、Entry)
小明和完美序列 知识点: //导包:HashMap、Map、Entry import java.util.HashMap; import java.util.Map; import java.util.Map.Entry;public class Main {public static void main(String [] args) { //创建Map(HashMap)对象 M…...
【hexo博客配置】hexo icarus主题配置
配置icarus 步骤一:下载icarus github网址:[hexo-theme-icarus](ppoffice/hexo-theme-icarus: A simple, delicate, and modern theme for the static site generator Hexo. (github.com)) 可以从这个网址上下载zip文件,解压后,…...
建表时如何合理选择字段类型
前言 我们在建表的时候关于字段类型的选择会有这么几类人: 严谨型 严格调研每个字段可能的大小,然后根据不同字段类型的限制,进行选择,这一类人在创建关系型数据表的时候是没有问题的。图自己省事型 把所有字段都设置为String&a…...
Qt Creator插件
这里以Qt Creator 4.15.2版本的源码为示例进行分析 源码结构如下,为了追溯其插件加载过程,从main.cpp入手 Qt Creator的插件目录,生成的插件,好几十个呢 Qt Creator插件的读取 int main(int argc, char **argv)中以下代码创建插…...
AI全栈大模型工程师(十九)Semantic Kernel
文章目录 Semantic KernelSK 的开发进展SK 的生态位SK 基础架构后记 Semantic Kernel 先比较下 Semantic Kernel 和 LangChain。 Semantic KernelLangChain出品公司微软LangChain AI支持语言Python、C#、Java、TypeScriptPython、TypeScript开源协议MITMIT被应用在Microsoft …...
Dubbo 的服务请求失败怎么处理?
本文引用mic老师面试文档 今天分享的面试题,几乎是 90%以上的互联网公司都会问到的问题。 “Dubbo 的服务请求失败怎么处理”? 对于这个问题,我们来看一下普通人和高手的回答。 普通人 嗯… 我记得, Dubbo 请求处理失败以后&a…...
存储虚拟化讲解
目录 存储虚拟化的分类 按照虚拟化发生的位置分类 基于主机的虚拟化 基于存储设备的虚拟化 基于网络的虚拟化 按照虚拟化实现方式分类 带内虚拟化 带外虚拟化 按照虚拟化的对象分类 虚拟机磁盘类型 按照磁盘的特性分类 按照磁盘的安全性分类 什么是虚拟化 存储虚拟…...
[云原生案例2.1 ] Kubernetes的部署安装 【单master集群架构 ---- (二进制安装部署)】节点部分
文章目录 1. 常见的K8S安装部署方式1.1 Minikube1.2 Kubeadm1.3 二进制安装部署 2. Kubernetes单master集群架构 ---- (二进制安装部署)2.1 前置准备2.2 操作系统初始化2.3 部署 docker引擎 ---- (所有 node 节点)2.4 部署 etcd 集…...
Apache ActiveMQ 远程代码执行漏洞影响范围
漏洞相关信息 项目内容漏洞名称Apache ActiveMQ 远程代码执行漏洞 漏洞描述 组件名称:Apache ActiveMQ 漏洞类型:远程代码执行 利用条件: 1、用户认证:不需要用户认证 2、触发方式:网络可访问 ActiveMQ的61616端…...
如何规划并新建大数据平台的独立生产域?5步走
一般来说,大数据平台包括以下4类数据生产域——生产生态环境(正式生产环境)、开发和测试环境、培训和演示环境、灾备环境。各生产域在由平台提供资源、安全、监控、故障恢复等保障的同时,不同的生产域之间还需要严格隔离ÿ…...
工程车云管家|叉车智能管家安卓主板方案
工程车云管家是一款功能强大的设备管理和调度系统,它可以实时追踪工程车或机械设备的地理位置、视频、行驶轨迹、油位油耗、工作时长和地点、以及运行状况等信息,并将这些数据通过云平台存储、分析,并发送到管理者的手机上。这使得管理者能够…...
大数据学习之Spark性能优化
文章目录 Spark三种任务提交模式宽依赖和窄依赖StageSpark Job的三种提交模式 Shuffle机制分析未优化的Hash Based Shuffle优化后的Hash Based ShuffleSort-Based Shuffle Spark之checkpointcheckpoint概述checkpoint与持久化的区别checkPoint的使用checkpoint源码分析 Spark程…...
个人服务器到期,项目下线,新的开始
告别旧服务器 2023.11.06服务器到期,所有项目正式下线 时间真的过的很快,从开始踏入编程的大门,到现在不知不觉已经陆续经手了两台服务器了,目前这台服务器是一年前的阿里云活动白嫖的嘿嘿嘿,该服务器上目前运行的项…...
arcgis 网络分析 生成可达范围/等时线
需求:生成从地铁站步行10分钟可达的范围面图层。 线图层预处理 在精度要求不是很高的情况下,可采用OSM路网,从中剔除不允许步行的道路类型:高速公路、快速路。 在路网图层中新增一个字段“步行时间”,用字段计算器&…...
npm切换镜像源
一,切换 npm 镜像源 npm 存储包文件的服务器在国外,速度很慢,所以我们需要解决这个问题。 国内淘宝的开发团队把 npm 在国内做了一个备份,网址是:http://npm.taobao.org/。 # 查看当前的源 npm config ls # 在上面命令…...
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> …...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...
用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
怎么让Comfyui导出的图像不包含工作流信息,
为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐) 在 save_images 方法中,删除或注释掉所有与 metadata …...
抽象类和接口(全)
一、抽象类 1.概念:如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象,这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法,包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中,⼀个类如果被 abs…...
【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅
目录 前言 操作系统与驱动程序 是什么,为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中,我们在使用电子设备时,我们所输入执行的每一条指令最终大多都会作用到硬件上,比如下载一款软件最终会下载到硬盘上&am…...
