# 源码分析 sync.Once
## 源码
```
func (o *Once) Do(f func()) {
if atomic.LoadUint32(&o.done) == 1 {
return
}
// Slow-path.
o.m.Lock()
defer o.m.Unlock()
if o.done == 0 {
defer atomic.StoreUint32(&o.done, 1)
f()
}
}
```
## 疑问
+ 为什么要把原子操作和锁一起用?
+ 我没能理解为什么要使用原子操作,试想如果o.Do已经成功执行过一次的情况,此时o.done的值为1,如果同时有100个线程调用o.Do,那么由于 atomic.LoadUint32(&o.done)是原子的,所以这一百个线程其实是排队依次读取这个值的,影响了并发性能;如果不用原子操作是不是会更好,这一百个线程就可以同时读取o.done的值;由于有锁,所以对o.done的赋值操作是单线程的,也没必要使用原子操作;修改后代码如下:
```
func (o *Once) Do(f func()) {
if o.done == 1 {
return
}
// Slow-path.
o.m.Lock()
defer o.m.Unlock()
if o.done == 0 {
f()
o.done = 1
}
}
```
有疑问加站长微信联系(非本文作者)