單例模式,是一種常用的軟件設(shè)計模式,在它的核心結(jié)構(gòu)中只包含一個被稱為單例的特殊類。通過單例模式可以保證系統(tǒng)中一個類只有一個實例且該實例易于外界訪問,從而方便對實例個數(shù)的控制并節(jié)約系統(tǒng)資源。
1. 懶漢模式(Lazy Loading)
懶漢模式是開源項目中使用最多的一種,最大的缺點是非線程安全的
type singleton struct {
}
// private
var instance *singleton
// public
func GetInstance() *singleton {
if instance == nil {
instance = &singleton{} // not thread safe
}
return instance
}
2. 帶鎖的單例模式
type singleton struct {
}
var instance *singleton
var mu sync.Mutex
func GetInstance() *singleton {
mu.Lock()
defer mu.Unlock()
if instance == nil {
instance = &singleton{} // unnecessary locking if instance already created
}
return instance
}
這里使用了Go的sync.Mutex,其工作模型類似于Linux內(nèi)核的futex對象,具體實現(xiàn)極其簡單,性能也有保證
初始化時填入的0值將mutex設(shè)定在未鎖定狀態(tài),同時保證時間開銷最小
這一特性允許將mutex作為其它對象的子對象使用
3. 帶檢查鎖的單例模式
if instance == nil { // <-- Not yet perfect. since it's not fully atomic
mu.Lock()
defer mu.Unlock()
if instance == nil {
instance = &singleton{}
}
}
return instance
}
這是一個不錯的方法,但是還并不是很完美。因為編譯器優(yōu)化沒有檢查實例存儲狀態(tài)。如果使用sync/atomic包的話 就可以自動幫我們加載和設(shè)置標(biāo)記。
import "sync"
import "sync/atomic"
var initialized uint32
...
func GetInstance() *singleton {
if atomic.LoadUInt32(&initialized) == 1 {
return instance
}
mu.Lock()
defer mu.Unlock()
if initialized == 0 {
instance = &singleton{}
atomic.StoreUint32(&initialized, 1)
}
return instance
}
4.比較好的一種方式sync.Once
import (
"sync"
)
type singleton struct {
}
var instance *singleton
var once sync.Once
func GetInstance() *singleton {
once.Do(func() {
instance = &singleton{}
})
return instance
}
引文:
https://xiequan.info/go%E7%9A%84%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/