日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Golang基于sync.Once實現單例的操作代碼_Golang

作者:Hugo?Lei ? 更新時間: 2022-12-03 編程語言

在go里實現單例模式有多種方式:

  • 基于lock
  • 基于init函數
  • 基于sync.Once

本文介紹基于sync.Once的方式來實現單例,熟練掌握這種模式,并理解其底層原理,對大部分人來講已經完全夠用了。

基于sync.Once實現單例

// 其他package也可見,在其他地方也可以new新對象
// 但是最終調用Conn()方法時,都是用的single這個單例
// 1
type Driver struct {
	// 小寫字母開頭,外部不可訪問,所以new個Driver新對象也沒用
	// 2
	conn string
}

// 全局變量,指針默認值為nil
// 3
var single *Driver // 單例
var once sync.Once

// 對外暴露的公共方法
func (s *Driver) Conn() {
	fmt.Printf("conn=%s", single.conn) // do something
}

// 4
func GetDriverSingleton() *Driver {
	// 對GetDriverSingleton()方法的調用,都會執行once.Do()方法,只不過參數func()只會被執行一次
	// 若并發執行once.Do(),多個協程會阻塞,因內部是通過Mutex來控制
	once.Do(func() {
		single = new(Driver)
		single.conn = "single conn"
		time.Sleep(50 * time.Millisecond)
	})
	return single
}

單例類型定義Driver

Driver類的方法要支持跨包訪問,因此需要以大寫字母開頭。
小寫字母開頭,作用域僅限于包內部。

類Field conn

類變量conn需要小寫字母開頭,跨包不可訪問,避免在包外被修改。

但是包內還是有可能被修改。

once.Do(func() {})

每次調用GetDriverSingleton(),都會調用once.Do()方法,但是在once.Do()方法內部,僅會執行一次參數func(){},因此就保證了單例唯一初始化。

并發訪問once.Do()

不會有并發訪問問題,因once.Do()內部通過mutex來控制。

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

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

對外暴露方法Conn()

外部對Conn()方法的調用,最終都由單例single來實現。

重新new(Driver)會發生什么?

很遺憾,無法將構造函數改成private,也就是說,在包外部是可以通過new(Driver)來創建新的對象。

但無論是哪個對象,對公開方法Conn()的調用,最終都是由單例single來執行的。

原文鏈接:https://blog.csdn.net/hugo_lei/article/details/127537614

欄目分類
最近更新