目录
数据结构
type Once struct {
done uint32
m Mutex
}
done:标记是否已经执行
m:互斥锁
方法
func (o *Once) Do(f func()) {
if atomic.LoadUint32(&o.done) == 0 {
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()
}
}
Do:采用双重检测方式保证方法只调用一次
注意点
- LoadUint32 原子读,保证多个CPU同时访问同一内存地址时的正确性
- doSlow 方法为什么不需要使用 LoadUint32 方法获取 done 值?原因是 lock 本身就是原子的,所以不需要 LoadUint32
- 会出现两个线程同时满足了 atomic.LoadUint32(&o.done) == 0 这个条件,为了防止重复调用,所以需要再判断 o.done == 0
- 加上 defer 是为了 保证方法先被执行 再改状态