Once 结构体 和 Go()方法都是位于 sync 包下,主要为了保证 Do(func) 中的 func 只执行一次,用于单例模式是比较好的方案。
原理:
Once 结构体中,包含两个字段
type Once struct {
done uint32 // 用来记录func 已经执行的次数
m Mutex // 锁
}
func (o *Once) Do(f func()) {
if atomic.LoadUint32(&o.done) == 0 { // 利用 atomic 包中的方法保证计数同步
o.doSlow(f) // 执行方法,记录标记字段
}
}
func (o *Once) doSlow(f func()) {
o.m.Lock() // 锁住执行状态
defer o.m.Unlock() // 释放锁
if o.done == 0 { // 如果没执行过
defer atomic.StoreUint32(&o.done, 1) // 记录已经执行过
f() // 执行函数
}
}