Go单例模式理解

本文探讨了在Go语言中实现并发安全单例模式的常见错误、过度加锁的解决方案以及如何利用`sync.Once`实现惯用的并发安全单例模式,强调了在并发环境中正确使用单例的重要性。
摘要由CSDN通过智能技术生成

对于被Go语言天生支持并发的特性吸引来的跨语言学习者来说,我觉着掌握Go语言的语法并不是最难的,最难的是突破既有的思维定势,真正理解并发和使用并发来解决实际问题。

Go语言太容易实现并发了,以至于它在很多地方被不正确的使用了。

常见的错误

有一些错误是很常见的,比如不考虑并发安全的单例模式。就像下面的示例代码:

package singleton

type singleton struct {
   }

var instance *singleton

func GetInstance() *singleton {
   
	if instance == nil {
   
		instance = &singleton{
   }   // 不是并发安全的
	}
	return instance
}

在上述情况下,多个goroutine可以执行第一个检查,并且它们都将创建该singleton类型的实例并相互覆盖。无法保证它将在此处返回哪个实例,并且对该实例的其他进一步操作可能与开发人员的期望不一致。

不好的原因是,如果有代码保留了对该单例实例的引用,则可能存在具有不同状态的该类型的多个实例,从而产生潜在的不同代码行为。这也成为调试过程中的一个噩梦,并且很难发现该错误,因为在调试时,由于运行时暂停而没有出现任何错误,这使非并发安全执行的可能性降到了最低,并且很容易隐藏开发人员的问题。

激进的加锁

也有很多对这种并发安全问题的糟糕解决方案。使用下面的代码确实能解决并发安全问题,但会带来其他潜在的严重问题,通过加锁把对该函数的并发调用变成了串行。

var mu Sync.Mutex

func GetInstance() *singleton {
   
    mu.Lock()                    // 如果实例存在没有必要加锁
    defer mu.Unlock()

    if instance == nil {
   
        instance = &singleton{
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值