Golang学习笔记_27——单例模式

news/2025/2/12 13:58:56/

Golang学习笔记_24——泛型
Golang学习笔记_25——协程Golang学习笔记_25——协程
Golang学习笔记_26——通道


文章目录

    • 单例模式
      • 1. 介绍
      • 2. 应用场景
      • 3. 实现
        • 3.1 饿汉式
        • 3.2 懒汉模式
    • 源码


单例模式

1. 介绍

单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问这个实例。

这种模式在很多场景下非常有用,比如数据库连接池、日志系统等,这些场景中我们通常希望在整个应用程序中只有一个对象来负责相关的操作,避免资源的浪费和数据的不一致

2. 应用场景

  • 数据库连接池:在应用程序中,数据库连接的创建和销毁是比较消耗资源的操作。使用单例模式可以确保整个应用程序只有一个数据库连接池实例,多个地方需要获取数据库连接时都从这个连接池中获取,这样可以有效地管理数据库连接,提高性能并节省资源。
  • 日志系统:一个应用程序通常只需要一个日志记录器来统一记录各种操作信息。单例模式可以保证整个系统只有一个日志记录器实例,所有的日志记录操作都通过这个实例来完成,方便对日志进行统一管理和配置。
  • 配置管理:对于应用程序的配置信息,如服务器端口号、数据库连接参数等,使用单例模式可以确保整个应用程序只有一个配置管理实例,这样可以方便地在不同的模块中获取和修改配置信息,并且保证配置信息的一致性。

3. 实现

3.1 饿汉式
type Singleton struct{}var singleInstance *Singleton = &Singleton{}func GetInstance() *Singleton {return singleInstance
}func test1() {instance1 := GetInstance()instance2 := GetInstance()fmt.Println(instance1 == instance2)
}

说明
这种方式在程序启动时就初始化了单例实例singleInstance。&Singleton{}创建了一个Singleton结构体的实例,并将其赋值给singleInstance。

GetInstance函数只是简单地返回这个已经初始化好的实例。这种方式被称为饿汉式,因为实例是在程序开始时就 “急切” 地创建好了,而不管是否马上会被用到。

优点是实现简单,并且在多线程环境下也是安全的,因为实例在任何线程访问之前就已经创建好了。

缺点是如果单例的初始化过程很复杂或者资源消耗大,可能会导致程序启动变慢。

3.2 懒汉模式

线程不安全


type Singleton struct{}var singleInstance *Singleton
// 懒汉式(非线程安全)
func GetInstance2() *Singleton {fmt.Println("GetInstance2")if singleInstance == nil {singleInstance = &Singleton{}}return singleInstance
}func test1() {
instance1 := GetInstance()
instance2 := GetInstance()
fmt.Println(instance1 == instance2)
}

懒汉式单例模式。在GetInstance函数中,首先检查singleInstance是否为nil。如果是,就创建一个Singleton结构体的新实例并赋值给singleInstance,然后返回这个实例

线程安全

type Singleton struct{}var singleInstance *Singleton// 懒汉式(线程安全)
var mutex sync.Mutexfunc GetInstance3() *Singleton {fmt.Println("GetInstance3")mutex.Lock()defer mutex.Unlock()if singleInstance == nil {singleInstance = &Singleton{}}return singleInstance
}func test1() {
instance1 := GetInstance()
instance2 := GetInstance()
fmt.Println(instance1 == instance2)
}

为了在多线程环境下正确地实现懒汉式单例模式,引入了互斥锁sync.Mutex

在GetInstance函数中,首先调用mutex.Lock()获取锁,这确保了同一时刻只有一个线程能够进入临界区

使用defer mutex.Unlock()可以保证在函数返回之前释放锁。这样,即使多个线程同时调用GetInstance函数,也能保证只有一个线程会创建singleInstance实例,从而保证了单例模式的正确性。

type Singleton struct{}var singleInstance *Singletonvar once sync.Oncefunc GetInstance4() *Singleton {fmt.Println("GetInstance4")once.Do(func() {fmt.Println("just once!")singleInstance = &Singleton{}})return singleInstance
}func test1() {
instance1 := GetInstance()
instance2 := GetInstance()
fmt.Println(instance1 == instance2)
}

once.Do 方法会确保传入的匿名函数只会被执行一次

源码

package singletonimport ("fmt""sync"
)type Singleton struct{}// 饿汉式
// var singleInstance *Singleton = &Singleton{} // 懒汉式直接在程序运行时创建
func GetInstance1() *Singleton {fmt.Println("GetInstance1")return singleInstance
}var singleInstance *Singleton// 懒汉式(非线程安全)
func GetInstance2() *Singleton {fmt.Println("GetInstance2")if singleInstance == nil {singleInstance = &Singleton{}}return singleInstance
}// 懒汉式(线程安全)
var mutex sync.Mutexfunc GetInstance3() *Singleton {fmt.Println("GetInstance3")mutex.Lock()defer mutex.Unlock()if singleInstance == nil {singleInstance = &Singleton{}}return singleInstance
}// 使用sync.Once实现
var once sync.Oncefunc GetInstance4() *Singleton {fmt.Println("GetInstance4")once.Do(func() {fmt.Println("just once!")singleInstance = &Singleton{}})return singleInstance
}// 测试方法
func test1() {//instance1 := GetInstance1()//instance2 := GetInstance1()//instance1 := GetInstance2()//instance2 := GetInstance2()//instance1 := GetInstance3()//instance2 := GetInstance3()instance1 := GetInstance4()instance2 := GetInstance4()fmt.Println(instance1 == instance2)
}

http://www.ppmy.cn/news/1564909.html

相关文章

Visual Studio Code + Stm32 (IAR)

记录一下, 以前看别人在 vsc 下配置 stm32 工程非常麻烦。 最近,突然发现, iar 官方出了两个插件, iar build 、 iar C-Spy 安装之后,配置一下 iar 软件路径。 然后,直接打开工程目录,编译…

一文夯实垃圾收集的理论基础

如何判断一个引用是否存活 引用计数法 给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加 1;当引用失效,计数器就减 1;任何时候计数器为 0 的对象就是不可能再被使用的。 优点:可即刻回收垃圾&a…

第十二章:算法与程序设计

文章目录: 一:基本概念 1.算法与程序 1.1 算法 1.2 程序 2.编译预处理 3.面向对象技术 4.程序设计方法 5.SOP标志作业流程 6.工具 6.1 自然语言 6.2 流程图 6.3 N/S图 6.4 伪代码 6.5 计算机语言 二:程序设计 基础 1.常数 …

抖音小程序一键获取手机号

前端代码组件 <button v-if"!isFromOrderList"class"get-phone-btn" open-type"getPhoneNumber"getphonenumber"onGetPhoneNumber">一键获取</button>// 获取手机号回调onGetPhoneNumber(e) {var that this tt.login({f…

element-plus中的table为什么相同的数据并没有合并成一个

我想把所有的第一列的名字相同的内容合并。我发现只有相邻的数据合并了。实际上我想做到的是所有的后端给的数据&#xff0c;不管他的顺序怎样的&#xff0c;只有deviceTypeName 一样的都合并的。 在 element-plus 的 table 中&#xff0c;数据合并行通常是基于相邻行的数据进行…

ASP.NET Core全球化与本地化:打造多语言应用

一、引言 在经济全球化浪潮的席卷下&#xff0c;软件应用的受众早已突破地域限制&#xff0c;走向全球各个角落。为了满足不同地区用户的语言需求&#xff0c;ASP.NET Core 应用开发中&#xff0c;全球化与本地化的实现显得尤为关键。全球化旨在让应用程序具备适应不同国家和地…

macOS 安装JDK17

文章目录 前言介绍新特性下载安装1.下载完成后打开downloads 双击进行安装2.配置环境变量3.测试快速切换JDK 小结 前言 近期找开源软件&#xff0c;发现很多都已经使用JDK17springboot3 了&#xff0c;之前的JDK8已经被替换下场&#xff0c;所以今天就在本机安装了JDK17&#…

出海工具集

群聊分享的一个工具集合&#xff0c;看了几个&#xff0c;感觉有点子用&#xff0c;收藏一波&#xff0c;下面有GitHub的地址&#xff1b;吃水不忘挖井人&#xff1b; GitHub地址 &#x1f4da; 分类 目录导航 Web 开发框架或模板Chrome 插件开发前端开发后端开发数据库管理对…