sync/atomic不是替代sync.mutex的万能方案,而是专用于简单共享变量的无锁同步原语;atomic.addint64只接受int64,因cpu原子指令要求严格字长与对齐,int类型平台依赖且不保证8字节对齐,传int会编译失败。

直接说结论:sync/atomic 不是“替代 sync.Mutex 的万能方案”,而是专用于简单共享变量的无锁同步原语——用错场景反而引入隐蔽 bug。
atomic.AddInt64 为什么不能直接用于 int?
Go 的原子操作函数严格绑定类型,atomic.AddInt64 只接受 *int64,传 *int 会编译失败(类型不匹配),传 *int32 也不行。这不是疏忽,而是设计使然:原子指令依赖底层 CPU 对齐和字长支持,混用类型可能触发未对齐访问或截断。
-
int在不同架构下可能是 32 位或 64 位(如 32 位 ARM 上int是 32 位),而atomic函数名明确限定字长,避免歧义 - 若需原子操作整数,显式声明为
int64或int32,例如:var counter int64,再用atomic.AddInt64(&counter, 1) - 别试图用
unsafe.Pointer强转绕过类型检查——这会破坏内存对齐保证,某些平台(如 ARM64)可能 panic 或静默出错
CompareAndSwap 是唯一能实现“条件更新”的原子操作
当你需要“仅当值为 A 时才设为 B”,且不能容忍中间状态被其他 goroutine 干扰,atomic.CompareAndSwapInt64 是唯一安全选择。它不是“高级版 Store”,而是带校验的原子写入。
- 典型误用:先
Load再Store—— 这两步之间存在竞态窗口,结果不可靠 - 正确模式是循环重试:
for { old := atomic.LoadInt64(&val); if atomic.CompareAndSwapInt64(&val, old, new) { break } } - 注意返回值:
atomic.CompareAndSwapInt64返回bool,必须检查是否成功;失败不等于错误,只是说明值已被他人修改 - CAS 本身不提供内存顺序语义,默认是
Relaxed,如需同步效果(如发布-订阅模型),得配合atomic.LoadAcquire/atomic.StoreRelease
atomic.Value 适合什么,不适合什么?
atomic.Value 是唯一支持任意类型(非基本类型)的原子操作封装,但它只保证“读写操作本身原子”,不保证内部数据结构的线程安全。
- 适用:安全替换整个对象,比如配置热更新:
var config atomic.Value; config.Store(&Config{Timeout: 5}) - 不适用:对
config.Load().(*Config).Timeout做修改——此时拿到的是指针,多个 goroutine 同时改同一 struct 字段仍会竞争 - 性能开销比整型原子操作高,因为涉及接口转换和堆分配,高频场景(如每毫秒调用)慎用
- 不能用于 nil 接口值的 CAS 判断——
atomic.Value的Load永远返回接口值,哪怕存的是nil,需额外判空逻辑
最易被忽略的一点:原子操作不解决“逻辑一致性”。比如两个相关字段 count 和 lastUpdated 需同步变更,单个 atomic 函数无法覆盖——这时必须退回到 sync.Mutex 或重新设计数据结构(如用单个 struct + atomic.Value 整体替换)。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











