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

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


文章目录

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

单例模式

1. 介绍

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

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

2. 应用场景

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

3. 实现

3.1 饿汉式
go 复制代码
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 懒汉模式

线程不安全

go 复制代码
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,然后返回这个实例

线程安全

go 复制代码
type Singleton struct{}

var singleInstance *Singleton

// 懒汉式(线程安全)
var mutex sync.Mutex

func 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实例,从而保证了单例模式的正确性。

go 复制代码
type Singleton struct{}

var singleInstance *Singleton

var once sync.Once

func 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 方法会确保传入的匿名函数只会被执行一次

源码

go 复制代码
package singleton

import (
	"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.Mutex

func GetInstance3() *Singleton {
	fmt.Println("GetInstance3")
	mutex.Lock()
	defer mutex.Unlock()
	if singleInstance == nil {
		singleInstance = &Singleton{}
	}
	return singleInstance
}

// 使用sync.Once实现
var once sync.Once

func 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)
}
相关推荐
ljt272496066110 分钟前
Compose笔记(六十九)--Pager
笔记
学历真的很重要21 分钟前
LangChain V1.0 Context Engineering(上下文工程)详细指南
人工智能·后端·学习·语言模型·面试·职场和发展·langchain
koo36432 分钟前
pytorch深度学习笔记13
pytorch·笔记·深度学习
崎岖Qiu1 小时前
【OS笔记36】:文件存储空间管理(一)- 空闲区表法
笔记·操作系统·存储管理·文件系统·os
菩提小狗1 小时前
Sqlmap双击运行脚本,双击直接打开。
前端·笔记·安全·web安全
码农小韩1 小时前
基于Linux的C++学习——动态数组容器vector
linux·c语言·开发语言·数据结构·c++·单片机·学习
嵌入式-老费2 小时前
外壳3D结构设计(学习的方法)
学习
代码游侠2 小时前
应用——智能配电箱监控系统
linux·服务器·数据库·笔记·算法·sqlite
山土成旧客2 小时前
【Python学习打卡-Day40】从“能跑就行”到“工程标准”:PyTorch训练与测试的规范化写法
pytorch·python·学习
Yyuanyuxin2 小时前
保姆级学习开发安卓手机软件(一)--安装软件及配置
学习