單例模式是一種經常使用的軟件設計模式。在它的核心結構中只包含一個被稱爲單例類的特殊類。經過單例模式能夠保證系統中一個類只有一個實例並且該實例易於外界訪問,從而方便對實例個數的控制並節約系統資源。若是但願在系統中某個類的對象只能存在一個,單例模式是最好的解決方案。設計模式
1.Go實現非線程安全的單例模式(懶漢 就是很懶的單例 哈哈):安全
kage singleton type singleton struct { } var instance *singleton func GetInstance() *singleton { if instance == nil { instance = &singleton{} // <--- NOT THREAD SAFE } return instance }
非線程安全的單例模式是你們用得最多的一種。在Github上面的開源項目有不少都使用了非線程安全的。多線程
這種寫法lazy loading很明顯,可是致命的是在多線程不能正常工做。性能
2.Go實現帶線程鎖的單例模式優化
varmu Sync.Mutex func GetInstance()*singleton{ mu.Lock() // <--- Unnecessary locking if instance already created defer mu.Unlock() ifinstance==nil{ instance=&singleton{} } returninstance }
這裏用了Go的sync/mutexui
sync/mutext是Go語言底層基礎對象之一,用於構建多個goroutine間的同步邏輯,所以被大量高層對象所使用。atom
其工做模型相似於Linux內核的futex對象,具體實現極爲簡潔,性能也有保證。線程
mutex對象僅有兩個數值字段,分爲爲state(存儲狀態)和sema(用於計算休眠goroutine數量的信號量)。
初始化時填入的0值將mutex設定在未鎖定狀態,同時保證時間開銷最小。
這一特性容許將mutex做爲其它對象的子對象使用。設計
3.帶檢查鎖的的單例模式對象
func GetInstance()*singleton{ ifinstance==nil{ // <-- Not yet perfect. since it's not fully atomic mu.Lock() defer mu.Unlock() ifinstance==nil{ instance=&singleton{} } } returninstance }
這是一個不錯的方法,可是還並非很完美。由於編譯器優化沒有檢查實例存儲狀態。若是使用sync/atomic包的話 就能夠自動幫咱們加載和設置標記。
rt "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 }
我的以爲比較好的在go中使用單例設計的是這種
packagesingleton import( "sync" ) typesingletonstruct{ } varinstance *singleton varonce sync.Once func GetInstance()*singleton{ once.Do(func(){ instance=&singleton{} }) returninstance }
經過使用sync.Once 包能夠實現線程安全的單例模式。
若是寫得有什麼不對地方歡迎指出。
轉自:https://xiequan.info/go%E7%9A%84%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/