直接用 atomic.AddInt64、atomic.LoadInt64 等函数操作可寻址且 8 字节对齐的 int64 变量可保证并发安全;错用类型、地址未对齐或混用普通读写会导致 panic 或 data race。

直接用 atomic.AddInt64、atomic.LoadInt64 等函数操作可寻址的 int64 变量,就能保证并发安全;但错用类型、地址未对齐、混用普通读写,会立刻 panic 或产生 data race。
为什么 ++ 和 += 不能用于并发计数器
因为 total++ 是“读-改-写”三步非原子操作:goroutine A 读到 100,B 也读到 100,A 加 1 写回 101,B 加 1 也写回 101——结果丢失一次递增。Go 的 go run -race 会明确报出 Data race on variable 'total'。
必须用原子函数替代,例如:
var counter int64 atomic.AddInt64(&counter, 1) // ✅ 安全
-
++、+=、=操作永远不安全,无论变量是否全局或加了注释 - 哪怕只读(如
if counter > 100),也必须用atomic.LoadInt64(&counter),否则无法保证看到最新值 - 不要试图“只在写时用 atomic,读时不用”——内存可见性不成立
int64 必须自然对齐,否则 runtime panic
在 amd64/arm64 上,atomic.LoadInt64 要求地址 8 字节对齐;若结构体中 int64 字段偏移不是 8 的倍数(比如前面有个 uint32),运行时直接触发 invalid memory address or nil pointer dereference。
立即学习“go语言免费学习笔记(深入)”;
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
验证方式:
import "unsafe"
type Bad struct { a uint32; b int64 }
fmt.Println(unsafe.Offsetof(Bad{}.b) % 8) // 输出 4 → ❌ 危险
- ✅ 正确做法:把
int64放结构体开头,或手动 padding:type Good struct { _ [4]byte; b int64 } - ✅ 更稳妥:用 Go 1.19+ 的类型安全原子类型,如
atomic.Int64,它内部自动处理对齐和封装 - ❌ 不要对
map值、函数返回的 struct 字面量字段、临时变量取址传给 atomic 函数
Load/Store 不是临界区,别当成 mutex 用
atomic.LoadUint64 和 atomic.StoreUint64 只保障单次读或写原子,不提供“读-判断-写”的原子性。下面代码有竞态:
if atomic.LoadUint64(&counter) > 100 {
alert() // ❌ 多个 goroutine 可能同时进入
}
- ✅ 安全场景:纯计数、状态标志切换(如
atomic.StoreInt32(&state, 1))、配置热更新(配合atomic.Value) - ❌ 危险场景:“读值→做判断→条件写入”,必须用
atomic.CompareAndSwap*手动循环实现,或退回到sync.Mutex - ⚠️ 注意:
atomic.Value要求存储的值可比较(如 struct 不能含map或func),且每次Store是整体替换,不是字段级更新
CAS 不是条件自增,而是乐观重试基础
atomic.CompareAndSwapInt64(&x, 10, 11) 只在 x == 10 时才设为 11 并返回 true;它本身不加法、不判断大小、不重试。想实现“仅当小于阈值时才加 1”,得自己写循环:
for {
old := atomic.LoadInt64(&x)
if old >= 100 {
break
}
if atomic.CompareAndSwapInt64(&x, old, old+1) {
break
}
}
- CAS 循环失败通常是因为其他 goroutine 在你 Load 和 CAS 之间修改了值,所以必须重试
- 没有内置的“原子条件递增”,别幻想
atomic.AddIfLessThan这种函数存在 - 高竞争下 CAS 循环可能饥饿,此时应评估是否该换锁或分片计数
最易被忽略的是:所有对同一变量的访问——无论读、写、增、交换——都必须统一走 atomic 函数;混用普通操作,哪怕只有一处,整个并发安全就崩了。

















