golang的另一种锁竞争解决方案,基于atomic
/**
atomic 原子操作,只针对go中的一些基本数据类型使用:int32、int64、uint32、uint64、uintptr(uintptr 是 Go 内置类型,表示无符号整数,可存储一个完整的地址)
*/
var (
x int64
wg sync.WaitGroup
)
func AmAdd() {
//通过 atomic 原子操作,保证数据操作的原子性,结果一定是500
atomic.AddInt64(&x, 1)
//直接x++,非原子操作,数据结果不准确,得到的结果可能是400多
//x++
//还可以通过sync.Mutex同步锁实现,加锁性能开销大
wg.Done()
}
func TestAtomic(t *testing.T) {
start := time.Now()
for i := 0; i < 500; i++ {
wg.Add(1)
go AmAdd() // 原子操作版Add函数,是并发安全的,性能优于加锁版
}
end := time.Now()
wg.Wait()
fmt.Println(x)
fmt.Println(end.Sub(start).Seconds())
}
atomic和mutex的区别
1.atomic的包处于sync/atomic,mutex则是sync下的包
2.atomic是对cpu底层进行原子操作,不能通过程序干预。而mutex则是在语言层面的,操作自由度较高。
3.atomic省去了lock和unlock的操作,代码比较简洁
4.atomic因为其在底层就已封装好的特性,所以它在goroutine下的运行表现是连续不间断的;而mutex则在goroutine运行间由于锁的等待或持有等情况,断断续续地执行
5.atomic总体运行较快,但是如果存储数据的非常巨大,它的性能会大打折扣。因为每次更新atomic的数据,都会进行一次数据复制,数据越大效率下降越大
