双重锁定(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 {} 只被创建一次。