这是我参与「第五届青训营 」伴学笔记创作活动的第12天
开启了两个 goroutine 分别执行 add 函数,这两个 goroutine 在访问和修改全局的x变量时就会存在数据竞争,某个 goroutine 中对全局变量x的修改可能会覆盖掉另一个 goroutine 中的操作
互斥锁
保证同一时间只有一个 goroutine 可以访问共享资源
用sync包中提供的Mutex类型来实现互斥锁 (完全互斥的)
func (m *Mutex) Lock() 获取互斥锁
func (m *Mutex) Unlock() 释放互斥锁
var (
x int64
wg sync.WaitGroup // 等待组
m sync.Mutex // 互斥锁)
// add 对全局变量x执行5000次加1操作func add() {
for i := 0; i < 5000; i++ {
m.Lock() // 修改x前加锁
x = x + 1
m.Unlock() // 改完解锁
}
wg.Done()}
读写互斥锁
var rwm sync.RWMutex
func (rw *RWMutex) Lock() 获取写锁
func (rw *RWMutex) Unlock() 释放写锁
func (rw *RWMutex) RLock() 获取读锁
func (rw *RWMutex) RUnlock() 释放读锁
func (rw *RWMutex) RLocker() Locker 返回一个实现Locker接口的读写锁
sync.WaitGroup
声明:
var wg sync.WaitGroup
func (wg * WaitGroup) Add(delta int) 计数器+delta
(wg *WaitGroup) Done() 计数器-1
(wg *WaitGroup) Wait() 阻塞直到计数器变为0
sync.Once
确保某些操作即使在高并发的场景下也只会被执行一次,如init
func (o *Once) Do(f func())
var loadOnce sync.Once
loadOnce.func(loadpic)
sync.Once实现的并发安全的单例模式
type singleton struct {}
var instance *singleton
var once sync.Once
func GetInstance() *singleton {
once.Do(func() {
instance = &singleton{}
})
return instance
}
sync.Once其实内部包含一个互斥锁和一个布尔值:
互斥锁保证布尔值和数据的安全,而布尔值用来记录初始化是否完成。
sync.Map
Go 语言中内置的 map 不是并发安全的, 不能在多个 goroutine 中并发对内置的 map 进行读写操作
// 并发安全的map: var m = sync.Map{}
func (m *Map) **Store**(key, value interface{}) 存储key-value数据
func (m *Map) **Load**(key interface{}) (value interface{}, ok bool) 查询key对应的value
func (m *Map) **LoadOrStore**(key, value interface{}) (actual interface{}, loaded bool) 查询或存储key对应的value
func (m *Map) **LoadAndDelete**(key interface{}) (value interface{}, loaded bool) 查询并删除key
func (m *Map) **Delete**(key interface{}) 删除key
func (m *Map) **Range**(f func(key, value interface{}) bool) 对map中的每个key-value依次调用f
原子操作
由内置的标准库sync/atomic提供