前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Golang实现线程安全的懒汉式单例模式

Golang实现线程安全的懒汉式单例模式

原创
作者头像
dddyge
发布2023-02-09 00:26:02
5520
发布2023-02-09 00:26:02
举报
文章被收录于专栏:思考与总结思考与总结

今天学习设计模式的时候看到了Java方面的双检式单例模式,由于JVM的指令重排序的问题,又在双检式的情况增添了更多的复杂性,于是我就去看看在Golang中是如何实现单例模式的。其实Golang中实现线程安全,同时又能够支持并发访问的方法也是双检法,他的复杂度封装在了sync包中的Once类中,也是通过采用Check -> Lock -> Check的方式来实现的,具体的代码如下

代码语言:javascript
复制
package sync

import (
	"sync/atomic"
)

// Once is an object that will perform exactly one action.
//
// A Once must not be copied after first use.
//
// In the terminology of the Go memory model,
// the return from f “synchronizes before”
// the return from any call of once.Do(f).
type Once struct {
	done uint32
	m    Mutex
}

func (o *Once) Do(f func()) {
	if atomic.LoadUint32(&o.done) == 0 {
		// Outlined slow-path to allow inlining of the fast-path.
		o.doSlow(f)
	}
}

func (o *Once) doSlow(f func()) {
	o.m.Lock()
	defer o.m.Unlock()
	if o.done == 0 {
		defer atomic.StoreUint32(&o.done, 1)
		f()
	}
}

可以看到Once类的Do方法通过传递一个匿名函数,这个匿名函数可以用来实现某个类的实例化过程。通过原子操作第一次检查类是否被实例化,如果没有实例化那么就取锁,取到锁后再次通过标志位检查类是否被实例化。这里有人会问了:那么为什么取到锁之后还要再次检查标志位呢?这里的回答是这样的:因为有可能两个协程并发通过了外层的检查,取到锁后没有二次检查就实例化了类,这样会造成多次重复实例化类,造成资源浪费。

那我们接下来看看使用sync.Once如何实例化单例:

代码语言:javascript
复制
package Singleton

import "sync"

/**
此包用于展示通过golang实现一个线程安全的单例模式, 懒汉式的线程安全的单例模式
 */

type singleton struct{}

var instance *singleton
var once sync.Once

func GetInstance() *singleton {
	once.Do(func() {
		instance = &singleton{}
	})
	return instance
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档