4.6、Golang 并发编程-atomic原子操作
原子变量
不加锁示例
go
package main
import (
"fmt"
"time"
)
var value = 100
func add() {
value++
}
func sub() {
value--
}
func main() {
for i := 0; i < 100; i++ {
go add()
go sub()
}
time.Sleep(time.Second * 2)
fmt.Printf("value: %v\n", value)
// value: 101
}
加锁示例
go
package main
import (
"fmt"
"sync"
"time"
)
var value = 100
var lock sync.Mutex
func add() {
lock.Lock()
value++
lock.Unlock()
}
func sub() {
lock.Lock()
value--
lock.Unlock()
}
func main() {
for i := 0; i < 100; i++ {
go add()
go sub()
}
time.Sleep(time.Second * 2)
fmt.Printf("value: %v\n", value)
// value: 100
}
atomic示例
cas: compare and swap (old new)
go
package main
import (
"fmt"
"sync/atomic"
"time"
)
var value int32 = 100
func add() {
atomic.AddInt32(&value, 1)
}
func sub() {
atomic.AddInt32(&value, -1)
}
func main() {
for i := 0; i < 100; i++ {
go add()
go sub()
}
time.Sleep(time.Second * 2)
fmt.Printf("value: %v\n", value)
// value: 100
}
原子操作详解
atomic 提供的原子操作能够确保任一时刻,只有一个goroutine对变量进行操作
善用atomic能够避免程序中出现大量的锁操作
atomic常见的操作有:
- 增减
- 载入 read
- 比较并交换cas
- 交换
- 存储 write
增减
go
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var value int32 = 100
atomic.AddInt32(&value, 1)
fmt.Printf("value: %v\n", value)
// value: 101
atomic.AddInt32(&value, -1)
fmt.Printf("value: %v\n", value)
// value: 100
}
读写
go
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var value int32 = 100
// read
atomic.LoadInt32(&value)
fmt.Printf("value: %v\n", value)
// value: 100
// write
atomic.StoreInt32(&value, 200)
fmt.Printf("value: %v\n", value)
// value: 200
}
比较并交换cas
go
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var value int32 = 100
// cas
ret := atomic.CompareAndSwapInt32(&value, 100, 200)
fmt.Printf("ret: %v\n", ret)
// ret: true
fmt.Printf("value: %v\n", value)
// value: 200
}
交换
go
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var value int32 = 100
// 直接交换
atomic.SwapInt32(&value, 200)
fmt.Printf("value: %v\n", value)
// value: 200
}