
Go atomic 原子操作深入从 CAS 原理到 lock-free 实战不写 unsafe也能 lock-free。Go 的 atomic 包已经覆盖了 95% 的无锁编程场景。一、为什么用 atomic锁是禁严控制临界区内任何写操作都会被锁保护。但锁的代价加锁 ~30ns解锁 ~30ns一旦抢锁所有协程死等atomic 直接走硬件CAS单指令完成更快更适合简单计数。二、核心 APIimportsync/atomicvarcountint64atomic.AddInt64(count,1)old:atomic.LoadInt64(count)swapped:atomic.CompareAndSwapInt64(count,old,old1)atomic.StoreInt64(count,42)unsafe.Pointer也能用varptr unsafe.Pointer atomic.StorePointer(ptr,unsafe.Pointer(node))old:atomic.LoadPointer(ptr)atomic.CompareAndSwapPointer(ptr,old,unsafe.Pointer(newNode))三、CAS 自旋锁typeSpinLockstruct{state*int32}funcNewSpinLock()*SpinLock{returnSpinLock{state:new(int32)}}func(s*SpinLock)Lock(){for!atomic.CompareAndSwapInt32(s.state,0,1){runtime.Gosched()// 让出避免 100% 占 CPU}}func(s*SpinLock)Unlock(){atomic.StoreInt32(s.state,0)}实测比 mutex 快 3-5 倍但只用于 hold 极短的临界区。四、原子计数器 单次访问typeHitsstruct{_[40]byte// 避免伪共享nuint64}varhits Hitsfunc(h*Hits)Inc(){atomic.AddUint64(h.n,1)}func(h*Hits)Get()uint64{returnatomic.LoadUint64(h.n)}填充防止伪共享多 CPU 同时 hot-write 时性能提升 30% 以上。五、双检锁与 sync.Oncevar(inst*Service once sync.Once)funcGetService()*Service{once.Do(func(){instService{}})returninst}sync.Once内部用原子 mutex比手写 double-checked 更安全。六、限流原子版typeTokenBucketstruct{tokensint64capacityint64refillRateint64// tokens/sec}func(t*TokenBucket)Allow()bool{for{tk:atomic.LoadInt64(t.tokens)iftk0{returnfalse}ifatomic.CompareAndSwapInt64(t.tokens,tk,tk-1){returntrue}}}简单场景够用高并发下 golang.org/x/time/rate 更稳定。七、踩坑清单atomic 操作必须 64 位对齐int64,uint64,uintptr结构体字段填充不要混用 atomic 与 mutex会让另一个线程读旧值CAS 自旋会让 CPU 100%务必runtime.Gosched或PAUSEmemory order默认 sequential consistency高级用法要看 runtime 文档八、总结与展望atomic 是 Go 并发的细粮。用对了就能免去 mutex 的负担用错了会引发非常隐蔽的竞态。未来计划Go 可能给标准库引入 typed atomic例如atomic.Int64使用体验再升级。九、参考文献Go 官方 sync/atomic 文档The Go Memory ModelMechanical Sympathy blog