GoLang 常见设计模式之: 单例模式

双重锁定(Double-Check Locking)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
package singleton

import "sync"

type singleton struct{}

var instance *singleton
var mu sync.Mutex

func GetSingleton() *singleton {
    if instance == nil {
        mu.Lock()
        defer mu.Unlock()
        if instance == nil {
            instance = &singleton{}
        }
    }
    return instance
}

外层 instance == nil 判断免去原来每次调用 GetSingleton () 都上锁,提高程序的执行效率。内层 instance == nil 判断则考虑了并发安全,在极端情况下多个 goroutine 同时走到加锁这一步,内层判断会在这里起到作用。

标准方案

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package singleton

import "sync"

type singleton struct{}

var instance *singleton
var once sync.Once

func GetSingleton() *singleton {
    once.Do(func() {
        instance = &singleton{}
    })
    return instance
}

Once 是一个结构体,在执行 Do 方法的内部通过原子(atomic)操作和加锁机制来保证并发安全,且 once.Do 能够保证多个 goroutine 同时执行时 &singleton {} 只被创建一次。