Golang实现设计模式--单例模式

单例模式:是一种常见的设计模式,用于确保一个类只有一个实例,并提供全局访问点。在实际应用中,有些对象只需要一个实例,比如线程池、数据库连接池等。使用单例模式可以确保只有一个实例存在,避免了资源的浪费和冲突。

Golang中实现单例模式的两种形式:饿汉式和懒汉式。

饿汉式单例模式

饿汉式单例模式是指在程序启动时就创建单例对象,以保证在程序运行期间只有一个实例。

go 复制代码
package single_hungry

import "fmt"

// 饿汉式单例模式

var s *singleInstance

type singleInstance struct {
}

func init() {
	s = newSingleInstance()
}

func newSingleInstance() *singleInstance {
	return &singleInstance{}
}

func (s *singleInstance) Work() {
	fmt.Println("single_hungry work function....")
}

type Instance interface {
	Work()
}

func GetSingleInstance() Instance {
	return s
}
go 复制代码
package main

import (
	"singleton/single_hungry"
)

func getSingleHungry() single_hungry.Instance {
	return single_hungry.GetSingleInstance()
}

func main() {
	s := getSingleHungry()
	s.Work()
}

懒汉式单例模式

懒汉式单例模式是指在需要使用单例对象时才创建实例,以避免在程序启动时就创建对象,浪费资源。

懒汉式存在并发问题,因此需要通过互斥锁的保护,保证初始化工作一定只会执行一次。

但也存在同时两个goroutine抢锁,gotoutine1抢到锁进行初始化,goroutine2等待锁释放,gotoutine1执行完初始化工作后释放锁,gotoutine2获得锁继续往下执行,这样情况会导致初始化工作不止执行一次。因此需要通过double check的思想,在加锁成功后进行第二次检查是否被初始化过

go 复制代码
package single_lazy

import (
	"fmt"
	"sync"
)

// 懒汉式单例模式

var (
	s     *singleInstance
	mutex sync.Mutex
)

type singleInstance struct {
}

func newSingleInstance() *singleInstance {
	return &singleInstance{}
}

func (s *singleInstance) Work() {
	fmt.Println("single_lazy work function....")
}

type Instance interface {
	Work()
}

func GetSingleInstance() Instance {
	if s != nil {
		fmt.Println("single_lazy already created....")
		return s
	}
	mutex.Lock()
	defer mutex.Unlock()
	if s != nil {
		fmt.Println("single_lazy already created.....")
		return s
	}
	fmt.Println("Creating single_lazy now.....")
	s = newSingleInstance()
	return s
}
go 复制代码
package main

import (
	"singleton/single_lazy"
	"time"
)

func getSingleLazy() single_lazy.Instance {
	return single_lazy.GetSingleInstance()
}

func main() {

	for i := 0; i < 30; i++ {
		go getSingleLazy()
	}
	time.Sleep(time.Second * 3)
}

通过sync.Onces实现懒汉式单例模式

go 复制代码
package single_once

import (
	"fmt"
	"sync"
)

// 懒汉式单例模式

var (
	s    *singleInstance
	once sync.Once
)

type singleInstance struct {
}

func newSingleInstance() *singleInstance {
	return &singleInstance{}
}

func (s *singleInstance) Work() {
	fmt.Println("single_once work function....")
}

type Instance interface {
	Work()
}

func GetSingleInstance() Instance {

	once.Do(func() {
		s = newSingleInstance()
	})
	return s
}

总结

饿汉式在程序加载时就创建好,不存在线程安全问题,没有加锁操作,不会出现同步控制的性能损耗;但在程序加载时就创建好实例,如果实例一直未被使用,会造成资源浪费,无法做到按需创建对象;适用于对性能要求较高的场景

懒汉式只在需要时创建对象,节省了内存资源,通过加锁保证了多线程环境下的同步访问;由于需要加锁进行同步控制,会造成一定的性能损耗。锁粒度较大,对整个方法加锁,即使只有第一次创建对象时需要同步,后续的访问也需要等待,适用于对性能要求不是很高的场景。

相关推荐
开心猴爷9 分钟前
Swift IPA 混淆在工程实践中的方式,分析仅依赖源码层混淆的局限性
后端
用户40993225021224 分钟前
Vue3 v-if与v-show:销毁还是隐藏,如何抉择?
前端·vue.js·后端
黄俊懿25 分钟前
【深入理解SpringCloud微服务】Seata(AT模式)源码解析——全局事务的回滚
java·后端·spring·spring cloud·微服务·架构·架构师
Java编程爱好者31 分钟前
SpringBoot启动太慢?几个优化技巧
后端
喷火龙8号32 分钟前
修复 Hertz + OpenTelemetry 链路追踪中的数据竞争问题
后端
JIngJaneIL34 分钟前
基于springboot + vue健康管理系统(源码+数据库+文档)
java·开发语言·数据库·vue.js·spring boot·后端
程序员小胖34 分钟前
每天一道面试题之架构篇|Java 热部署插件化架构设计
后端
幌才_loong36 分钟前
.NET 8 中 EF Core 的 DbContext 配置全解析
后端·.net
木木一直在哭泣37 分钟前
我把一个“U8 库存全量同步”从“能跑”改成“能长期稳定跑”:并发 + 全局限流 + 幂等复盘
后端
刘一说42 分钟前
Spring Boot中IoC(控制反转)深度解析:从实现机制到项目实战
java·spring boot·后端