atomic 轻量级锁
作者:matrix 发布时间:2026-04-30 分类:Golang

atomic 实际上就是一种“轻量级锁”的实现,但更准确地说,它是“无锁(lock-free)并发”的一种实现方式——直接使用 CPU 的原子指令来保证数据的并发安全
atomic使用底层硬件实现的,没有锁但是实现了锁的功能,不像Golang中Mutex、RWMutex锁使用的是软件层面实现开销大。
sync/atomic锁类型
包还提供了多个类型
布尔值
| 类型 | 描述 |
|---|---|
atomic.Bool |
原子布尔值(true/false) |
数值类型(适合计数器、状态码等)
| 类型 | 描述 | 方法示例 |
|---|---|---|
atomic.Int32 |
原子 32 位整数 | Add(), Load(), Store() |
atomic.Int64 |
原子 64 位整数 | 同上 |
atomic.Uint32 |
原子无符号 32 位整数 | 同上 |
atomic.Uint64 |
原子无符号 64 位整数 | 同上 |
atomic.Uintptr |
原子 uintptr(指针偏移等) | Swap(), CompareAndSwap() |
这些数值类型背后都是通过 atomic.AddInt64、atomic.LoadInt64 等封装来的。
任意值类型(适合共享配置、数据对象等)
| 类型 | 描述 |
|---|---|
atomic.Value |
通用的线程安全容器,支持任意类型的值存取 |
Example
看着以为简单,实际使用还是得注意
atomic.Bool
var flag atomic.Bool
func work(name string) {
// if !flag.Load() // 获取值。 如果这样 输出结果依然全是第一次进入 没有达到锁的效果
if flag.CompareAndSwap(false, true) {
fmt.Printf("name:%v, flag is false(第一次进入)\n", name)
time.Sleep(100 * time.Millisecond) // 模拟耗时
flag.Store(true) //写入值
return
}
fmt.Printf("name:%v, flag is true\n", name)
}
func main() {
for i := 0; i < 10; i++ {
go work(fmt.Sprint("goroutine:", i))
}
time.Sleep(time.Second * 5)
}
// output:
// name:goroutine:9, flag is true
// name:goroutine:3, flag is false(第一次进入)
// name:goroutine:8, flag is true
// name:goroutine:1, flag is true
// name:goroutine:7, flag is true
// name:goroutine:4, flag is true
// name:goroutine:6, flag is true
// name:goroutine:2, flag is true
// name:goroutine:5, flag is true
// name:goroutine:0, flag is true
关键是CompareAndSwap方法,只有第一个 GOroutine 做某事(比如只执行一次初始化),那就必须用 CompareAndSwap()
CompareAndSwap(false, true): 判断当前值是否 false,且设置 true 成功
atomic.Int64
并发计数器
var flag atomic.Int64
func work(addval int64) {
flag.Add(addval)
}
func main() {
for i := 0; i < 10000; i++ {
go work(int64(1))
}
time.Sleep(time.Second * 1)
fmt.Println(flag.Load())
}
//output:
// 10000
atomic.Value
允许定义自定义结构体
var flag atomic.Value
type Res struct {
v bool
}
func work(name int) {
// if flag.Load() != nil && flag.Load().(Res).v == false // 可能存在竞态问题,不能使用!!!
if flag.Load() != nil && flag.CompareAndSwap(Res{v: false}, Res{v: true}) { // 使用CompareAndSwap 才能保证原子性
//flag.Store(Res{v: true}) // 多余操作,CompareAndSwap内部会把Res{v: true}值赋上
time.Sleep(time.Second * 1)
fmt.Printf("name:%d 第一次执行\n", name)
return
}
fmt.Printf("name:%d 已操作\n", name)
}
func main() {
flag.Store(Res{v: false})
for i := 0; i < 10; i++ {
go work(i)
}
time.Sleep(time.Second * 2)
// fmt.Println(flag.Load())
fmt.Printf("%T\n", flag)
}
flag.CompareAndSwap(old, new) 第一个参数old,就表示期望获取的状态锁(false),获取到之后会把flag赋值为new