Golang基于sync.Once實現(xiàn)單例的操作代碼
在go里實現(xiàn)單例模式有多種方式:
- 基于lock
- 基于init函數(shù)
- 基于sync.Once
本文介紹基于sync.Once的方式來實現(xiàn)單例,熟練掌握這種模式,并理解其底層原理,對大部分人來講已經(jīng)完全夠用了。
基于sync.Once實現(xiàn)單例
// 其他package也可見,在其他地方也可以new新對象
// 但是最終調(diào)用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()方法的調(diào)用,都會執(zhí)行once.Do()方法,只不過參數(shù)func()只會被執(zhí)行一次
// 若并發(fā)執(zhí)行once.Do(),多個協(xié)程會阻塞,因內(nèi)部是通過Mutex來控制
once.Do(func() {
single = new(Driver)
single.conn = "single conn"
time.Sleep(50 * time.Millisecond)
})
return single
}
單例類型定義Driver
Driver類的方法要支持跨包訪問,因此需要以大寫字母開頭。
小寫字母開頭,作用域僅限于包內(nèi)部。
類Field conn
類變量conn需要小寫字母開頭,跨包不可訪問,避免在包外被修改。
但是包內(nèi)還是有可能被修改。
once.Do(func() {})
每次調(diào)用GetDriverSingleton(),都會調(diào)用once.Do()方法,但是在once.Do()方法內(nèi)部,僅會執(zhí)行一次參數(shù)func(){},因此就保證了單例唯一初始化。
并發(fā)訪問once.Do()
不會有并發(fā)訪問問題,因once.Do()內(nèi)部通過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()方法的調(diào)用,最終都由單例single來實現(xiàn)。
重新new(Driver)會發(fā)生什么?
很遺憾,無法將構(gòu)造函數(shù)改成private,也就是說,在包外部是可以通過new(Driver)來創(chuàng)建新的對象。
但無論是哪個對象,對公開方法Conn()的調(diào)用,最終都是由單例single來執(zhí)行的。
到此這篇關于golang實現(xiàn)單例的操作代碼的文章就介紹到這了,更多相關go單例內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
golang實現(xiàn)整型和字節(jié)數(shù)組之間的轉(zhuǎn)換操作
這篇文章主要介紹了golang實現(xiàn)整型和字節(jié)數(shù)組之間的轉(zhuǎn)換操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12
詳解Golang中errors包如何返回自定義error類型
這篇文章主要為大家詳細介紹了Golang中errors包如何返回自定義error類型,文中的示例代碼簡潔易懂,有需要的小伙伴可以跟隨小編一起學習一下2023-09-09

