Go同步原语与数据竞争:原子操作(atomic)

在Go并发编程中,当多个 goroutine 同时读写共享变量时,如果没有妥善同步,就会出现数据竞争(Data Race) 。Go 提供了 sync/atomic 包,用于实现轻量级的原子操作,避免使用锁所带来的性能开销。


一、什么是原子操作?

原子操作指的是在执行过程中不会被任何其他操作中断的操作。在多线程环境中,原子操作确保某个变量的读、写、加减等操作具有一致性和安全性。


二、常用原子操作函数

Go 的 sync/atomic 包支持以下常用操作,主要用于 int32int64uint32uint64unsafe.Pointer 等类型:

函数 说明
atomic.LoadInt32(&val) 原子读取值
atomic.StoreInt32(&val, new) 原子写入值
atomic.AddInt32(&val, delta) 原子加法(并返回新值)
atomic.CompareAndSwapInt32(&val, old, new) 原子比较并交换
同理还有 Int64Uint32Uint64Pointer 版本

三、使用示例

示例:并发计数器

go 复制代码
package main

import (
    "fmt"
    "sync"
    "sync/atomic"
)

func main() {
    var counter int32 = 0
    var wg sync.WaitGroup

    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            atomic.AddInt32(&counter, 1)
        }()
    }

    wg.Wait()
    fmt.Println("Final Counter:", counter) // 输出应该为 1000
}

这个例子中我们使用 atomic.AddInt32 来确保并发写入是安全的,避免了 race condition


四、CompareAndSwap:原子级条件更新

CompareAndSwap 是一个非常强大的函数,可用于实现无锁状态切换。

go 复制代码
var status int32 = 0

// 尝试将状态从 0 改为 1
if atomic.CompareAndSwapInt32(&status, 0, 1) {
    fmt.Println("切换状态成功")
} else {
    fmt.Println("状态已被修改")
}

如果当前值等于期望值,就会被新值替换;否则不做任何操作,适用于状态机、CAS 重试等场景。


五、原子 vs 锁

方面 原子操作(atomic) 锁(Mutex/RWMutex)
性能 极高(CPU级指令) 较低(涉及调度、抢占)
适用场景 简单计数、状态标记 复杂结构同步
编程复杂度 较高,易出错 较低,语义清晰
死锁风险 存在风险

六、使用注意事项

  • • 原子操作仅适用于简单变量的并发读写,如计数器、标志位。
  • • 不能对结构体、map、slice 等复杂类型直接使用。
  • • 原子操作不能和普通操作混用,否则仍可能产生竞态条件。
  • • 如需读写多个变量或复合结构,推荐使用 sync.Mutex

七、小结

  • sync/atomic 提供了高性能的原子操作,是无锁并发的核心工具。
  • • 适合用于计数器、自旋锁、状态标识等场景。
  • • 不适合管理复杂共享数据,不能代替所有同步手段。

相关推荐
前端小巷子20 分钟前
Webpack 5模块联邦
前端·javascript·面试
前端双越老师21 分钟前
为何前端圈现在不关注源码了?
面试·前端框架·源码
江城开朗的豌豆30 分钟前
Vue和React中的key:为什么列表渲染必须加这玩意儿?
前端·vue.js·面试
小鱼人爱编程1 小时前
Java基石--反射让你直捣黄龙
前端·spring boot·后端
hqxstudying1 小时前
J2EE模式---服务层模式
java·数据库·后端·spring·oracle·java-ee
GM_8281 小时前
【最新最完整】SpringAI-1.0.0开发MCP Server,搭建MCP Client 实战笔记(进阶+详细+完整代码)
java·后端·ai编程·springai·mcp
程序员爱钓鱼1 小时前
Go语言实战案例-滑动窗口最大值
后端·google·go
Victor3562 小时前
MySQL(163) 如何理解MySQL的隔离级别?
后端
Victor3562 小时前
MySQL(164)如何设置MySQL的隔离级别?
后端
代码老y3 小时前
ASP.NET Core 高并发万字攻防战:架构设计、性能优化与生产实践
后端·性能优化·asp.net