9.7 GO 单例模式

单例模式是常用的模式之一,一般介绍的单例模式有 饿汉式懒汉式 等,不管那种模式最终目的只有一个,就是只实例化一次,仅允许一个实例存在。

GO语言实现单例模式相对简单,这里考虑到并发,用到了sync.Mutex 和结构体sync.Once。

示例:

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. )
  6. var (
  7. lock *sync.Mutex = &sync.Mutex{}
  8. instance *Singleton
  9. )
  10. type Singleton struct {
  11. }
  12. func GetInstance() *Singleton {
  13. if instance == nil {
  14. lock.Lock()
  15. defer lock.Unlock()
  16. if instance == nil {
  17. instance = &Singleton{}
  18. fmt.Println("instance...")
  19. }
  20. }
  21. return instance
  22. }
  23. func main() {
  24. var s *Singleton
  25. s = GetInstance()
  26. s = GetInstance()
  27. fmt.Println(s)
  28. }

执行结果:

instance… &{}

通过结果可以看到只输出了一个instance…。

上面的实现方式还可以通过结构体sync.Once更优雅的实现。

示例:

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. )
  6. var (
  7. once sync.Once
  8. instance *Singleton
  9. )
  10. type Singleton struct {
  11. }
  12. func GetInstance() *Singleton {
  13. once.Do(func() {
  14. instance = &Singleton{}
  15. fmt.Println("instance...")
  16. })
  17. return instance
  18. }
  19. func main() {
  20. var s *Singleton
  21. s = GetInstance()
  22. s = GetInstance()
  23. fmt.Println(s)
  24. }

输出结果:

instance… &{}

通过sync.Once的源代码查看它是如何运行的

  1. func (o *Once) Do(f func()) {
  2. if atomic.LoadUint32(&o.done) == 1 {
  3. return
  4. }
  5. // Slow-path.
  6. o.m.Lock()
  7. defer o.m.Unlock()
  8. if o.done == 0 {
  9. defer atomic.StoreUint32(&o.done, 1)
  10. f()
  11. }
  12. }

sync.Once.Do(f func())使用加锁原子操作(代码包sync/atomic)来保证函数 f 只执行一次。

links