在Golang的并发编程中,当多个goroutine同时读写同一个共享变量时,普通的非原子操作会因为指令重排、缓存不一致等问题导致数据错误,而atomic包提供的原子操作可以保证对变量的修改是原子的,不需要额外的锁机制就能实现并发安全。

atomic原子操作的核心特性
atomic原子操作的核心是保证操作的不可分割性,一个原子操作在执行过程中不会被其他goroutine打断,所有操作要么全部完成,要么全部不执行。相比传统的互斥锁,原子操作的开销更小,适合简单的变量修改场景。
常用原子操作类型
- 基本类型的原子读写:针对int32、int64、uint32、uint64、uintptr、unsafe.Pointer等类型
- 原子算术操作:加法、减法等
- 原子比较并交换(CAS):先比较当前值是否符合预期,符合则替换
- 原子值:可以存储任意类型的原子容器
常用atomic函数实践
1. 原子加法操作
使用atomic.AddInt64可以对int64类型的变量进行原子加法,避免多个goroutine同时修改时的数据竞争。
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var count int64
var wg sync.WaitGroup
// 启动10个goroutine,每个累加1000次
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 1000; j++ {
// 原子加法,每次给count加1
atomic.AddInt64(&count, 1)
}
}()
}
wg.Wait()
// 最终输出应该是10000
fmt.Println("最终计数:", count)
}
2. 原子比较并交换(CAS)操作
CAS操作是很多无锁数据结构的基础,atomic.CompareAndSwapInt32会先检查当前值是否等于旧值,如果相等则将值替换为新值,返回true,否则返回false。
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var status int32 = 0
// 尝试将status从0改为1
swapped := atomic.CompareAndSwapInt32(&status, 0, 1)
if swapped {
fmt.Println("状态修改成功,当前状态:", status)
} else {
fmt.Println("状态修改失败,当前状态:", status)
}
// 再次尝试修改,此时旧值是0,实际值是1,修改失败
swapped = atomic.CompareAndSwapInt32(&status, 0, 2)
fmt.Println("第二次修改结果:", swapped, "当前状态:", status)
}
3. 原子值的使用
atomic.Value可以存储任意类型的值,并且保证读写操作的原子性,适合存储配置、状态等需要并发读写的场景。
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var config atomic.Value
// 存储初始配置
config.Store(map[string]string{"timeout": "10s"})
// 读取配置
currentConfig := config.Load().(map[string]string)
fmt.Println("初始配置:", currentConfig)
// 更新配置
newConfig := map[string]string{"timeout": "20s", "max_conn": "100"}
config.Store(newConfig)
// 读取更新后的配置
updatedConfig := config.Load().(map[string]string)
fmt.Println("更新后配置:", updatedConfig)
}
原子操作与互斥锁的选择
虽然原子操作性能更好,但并不是所有场景都适用,我们可以通过下面的对比来选择合适的同步方式:
| 对比维度 | atomic原子操作 | 互斥锁(sync.Mutex) |
|---|---|---|
| 适用场景 | 简单的单个变量读写、修改 | 复杂的多变量操作、代码块同步 |
| 性能开销 | 小,无上下文切换 | 较大,涉及 goroutine 阻塞唤醒 |
| 操作复杂度 | 仅支持预定义的基础操作 | 可以包裹任意复杂的逻辑 |
注意事项
- atomic操作仅保证单个操作的原子性,如果需要对多个变量进行原子修改,还是需要使用互斥锁
- 不要对已经使用atomic操作的变量再使用普通的非原子操作修改,否则会破坏原子性
- 对于64位整数,在32位平台上需要保证变量的地址是64位对齐的,否则可能导致程序崩溃
Golangatomic原子操作并发编程sync_atomic修改时间:2026-06-16 11:09:16