Golang单例模式学习笔记

前言

单例模式是常用的一种设计模式,一般用于比如客户端、连接的创建等,防止创建多个导致性能消耗。所以我认为单例模式的核心,就是"防止重复"。本文将在Golang中进行单例模式的实现。

实现

版本1------检测-创建

最基础的版本,就是依照"防止重复"来实现。代码如下:

go 复制代码
package main

type Test1 struct {
}

var t1 *Test1

func main() {

}

func NewT1() *Test1 {
	if t1 == nil {
		t1 = &Test1{}
	}
	return t1
}

可见,只是在创建前,进行了一个判定,如果为空 再创建。不为空则直接返回。

但是这样版本存在有问题------即线程不安全。比如多个goroutine中同时运行其去创建,那么就很容易导致创建重复。

对此,解决方案也很简单------加锁即可。

版本2------加锁-检测-创建

很简单粗暴的加个锁------这样就能保证只有一个去进行检测、创建。规避了问题。

go 复制代码
var mutex sync.Mutex


func NewT1() *Test1 {
	mutex.Lock()
	defer mutex.Unlock()

	if t1 == nil {
		t1 = &Test1{}
	}
	return t1
}

但是这样带来了新的问题:频繁的加锁、删锁,带来了巨大的性能损耗。诸如t1已经存在的情况,本该直接返回即可,但是却需要白白加锁一次。

版本3------检测-加锁-检测-创建

即所说的Check-Lock-Check模式。代码如下:

go 复制代码
func NewT1() *Test1 {
	if t1 == nil {

		mutex.Lock()
		defer mutex.Unlock()

		if t1 == nil {
			t1 = &Test1{}
		}
	}
	return t1
}

可以看到,就是在最开始的lock之前,进行一次检测。一个if判断的消耗还是很小的,如果存在再进入加锁创建的流程。

在Golang中,可以使用sync/atomic这个包,原子化的加载一个标志,来实现这套判断。

即:

go 复制代码
import "sync"
import "sync/atomic"

var initialized uint32
... // 此处省略

func GetInstance() *singleton {

    if atomic.LoadUInt32(&initialized) == 1 {  // 原子操作 
		    return instance
	  }

    mu.Lock()
    defer mu.Unlock()

    if initialized == 0 {
         instance = &singleton{}
         atomic.StoreUint32(&initialized, 1)
    }

    return instance
}
//此代码直接复制至原文------https://www.liwenzhou.com/posts/Go/singleton/

版本4------Golang常用的方式

饿汉和懒汉式

饿汉

饿汉模式,即像一个饿肚子人一样迫不及待的去享用美食。即 在程序加载的时候就创建并实例化,因此也无需考虑并发等情况。

示例:

go 复制代码
package main

import "fmt"

type Singleton struct {
	// 在这里定义单例对象的属性
}

var instance *Singleton = createInstance()

func createInstance() *Singleton {
	// 在这里创建并初始化单例对象
	return &Singleton{
		// 初始化单例对象的属性
	}
}

func GetInstance() *Singleton {
	return instance
}

func main() {
	// 使用单例模式获取实例
	singletonInstance := GetInstance()

	// 使用单例实例
	fmt.Println(singletonInstance)
}
//此代码复制自原文------https://i6448038.github.io/2023/12/16/singleton/

懒汉

顾名思义,懒得管...等用到时候再创建。此时程序已经启动并正在运行,此时创建实例可能会出现多线程的情况,所以要考虑并发问题。

上述的实现代码便是懒汉模式。

参考资料

https://www.liwenzhou.com/posts/Go/singleton/
https://i6448038.github.io/2023/12/16/singleton/

相关推荐
M78佐菲3 小时前
51单片机学习笔记:ds18b20要点整理
linux·笔记·嵌入式硬件·学习·51单片机
高亦真3 小时前
今天是学习嵌入式的第37天
linux·学习·算法
泡泡鱼(敲代码中)6 小时前
Python 字符串 str 完整学习笔记
python·学习
我不会起名字3227 小时前
一天一道算法题(34):回溯法的经典例题(子集)
java·数据结构·python·算法·golang·深度优先·力扣
kyrie_sakura8 小时前
python学习笔记15 -- Anaconda,Jupyter,numpy
python·学习·jupyter·numpy
PC2005-cloud10 小时前
Rust学习笔记:控制流——if、loop、while、for与match
笔记·学习·rust
彧azz10 小时前
DFS与BFS:图遍历的两大核心算法
数据结构·学习·算法·深度优先·广度优先
A心有千千结10 小时前
GO 使用 OpenTelemetry 进行编译时插桩,实现零码注入
数据库·golang·可观测性·观测云
kyrie_sakura11 小时前
python学习笔记14 -- FastAPI
笔记·python·学习·fastapi
来两个炸鸡腿11 小时前
【Datawhale2609】算子开发实战 task01-熟悉沐曦GPU
人工智能·学习·大模型