go 1.19起推荐直接用atomic.int64类型,它零值合法、封装内存序与对齐检查,避免arm/32位环境因不对齐触发sigbus;声明为var counter atomic.int64,嵌入struct时须为首个字段,且所有读写必须使用其load/store/add等方法。

直接用 atomic.Int64 声明就安全,别手写 int64 + atomic.AddInt64
Go 1.19 起推荐直接用 atomic.Int64 类型,它比裸 int64 配 atomic.AddInt64 更可靠。零值合法,方法封装了内存序和对齐检查,避免在 ARM 或 32 位环境因字段偏移不对齐触发 SIGBUS panic。
-
atomic.Int64是值类型,可直接声明:var counter atomic.Int64 - 嵌入 struct 时,必须放在**第一个字段**,否则无法保证 8 字节对齐(尤其前面有
[3]byte这类非对齐字段时) - 不要混用:一旦用了
atomic.Int64,所有读写都走它的Load()、Add()、Store()方法,别去取地址再传给旧式atomic.*Int64函数
需要「自增并返回旧值」?自己写循环 CAS,别用 Swap
atomic.Int64 没有 IncAndReturnOld() 这种方法,但业务常需要“先拿到当前值,再加 1”。不能用 Swap,因为它不校验原值,会覆盖别人刚写入的新值,造成丢失更新。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 正确做法是
Load+CompareAndSwap循环: for { old := c.Load(); if c.CompareAndSwap(old, old+1) { return old } }- 高争用下可能重试多次,但比锁轻量;若业务能接受“返回新值”,直接
c.Add(1)最简
什么时候必须换 sync.Mutex?不是性能问题,是表达力边界
atomic 只保单个变量的原子性,一旦逻辑跨步骤或跨字段,它就无能为力。这时换锁不是退让,而是回归语义清晰性。
- 典型场景:「如果计数器 atomic 无法一步完成
- 多个变量联动:比如计数器 + 最后更新时间戳 + 状态标志,必须一起更新,
atomic不支持批量操作 - 结构体字段类型不支持原子:如
float64、map、自定义 struct,只能用sync.Mutex或atomic.Value(后者要求类型固定)
atomic.AddInt64 传参错一个字,整个计数器就失效
老式写法仍常见,但极易出错:变量类型、地址传递、读写一致性三处任一出错,竞态立刻重现。
- 必须用
int64,不能用int(32 位平台不保证原子性) - 所有操作必须传指针:
atomic.AddInt64(&counter, 1),传值编译不过,但漏写&会导致静默错误 - 读也必须用
atomic.LoadInt64(&counter),直接counter读会看到陈旧值,且破坏 happens-before 关系 - 全局变量或 struct 字段安全;栈上局部变量(如函数内
var x int64)地址不一定对齐,尤其在 ARM 上会 panic
atomic 函数,只要变量没对齐,就是一颗定时炸弹。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










