文章目录

Go并发编程(六)atomic包

代码中的加锁操作因为涉及内核态的上下文切换会比较耗时、代价比较高。针对基本数据类型我们还可以使用原子操作来保证并发安全,因为原子操作是Go语言提供的方法它在用户态就可以完成,因此性能比加锁操作更好。Go语言中原子操作由内置的标准库sync/atomic提供。

使用

func TestMyAtomic()  {
// 写入
var a int64
atomic.StoreInt64(&a,10)
fmt.Println("写入a:",a)
// 修改
atomic.AddInt64(&a,1)
// 读取
b := atomic.LoadInt64(&a)
fmt.Println("读取a:",b)
// 交换,非cas,直接赋予新值
old := atomic.SwapInt64(&a,b)
fmt.Println("交换后旧值:",old)
fmt.Println("新值:",atomic.LoadInt64(&a))
// 比较并交换,只有跟期望值相等才会交换
flag := atomic.CompareAndSwapInt64(&a,10,10)
fmt.Println("比较并交换:",flag)
}

CAS

Compare And Swap 简称CAS,在sync/atomic包种,这类原子操作由名称以‘CompareAndSwap’为前缀的若干个函数代表。

声明如下

func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)
  • 调用函数后,会先判断参数addr指向的被操作值与参数old的值是否相等
  • 仅当此判断得到肯定的结果之后,才会用参数new代表的新值替换掉原先的旧值,否则操作就会被忽略。

swap

交换Swap
与CAS操作不同,原子交换操作不会关心被操作的旧值。
它会直接设置新值
它会返回被操作值的旧值
此类操作比CAS操作的约束更少,同时又比原子载入操作的功能更强

原理

如何保证原子性?

atomic包将底层提供的原子内存操作封装为go函数