golang中sync包实现了两种锁Mutex(互斥锁)和RWMutex(读写锁)
【1】互斥锁(和上厕所一样,用的时候把门锁上,不用的时候把门给关上)
其中Mutex为互斥锁,Lock()加锁,Unlock()解锁,使用Lock()加锁后,便不能再对其进行加锁,直到利用Unlock()解锁对其解锁后,才能再次加锁,适用于读写不确定场景,即读写次数没有明显的区别
----性能、效率都相对来说比较低
【2】读写锁
RWMutex是一个读写锁,其经常用于读次数远远多于写次数的场景
----在读的时候,数据之间不产生影响,写和读之间才会产生影响
不加锁的情况下并发执行
结果:在理论上,这个totalNum结果应该是0,无论协程怎么交替执行,最终想象的结果就是0
但是事实上:不是
问题出现的原因:(图解为其中一种可能得原因)
解决问题:
有一个机制:确保:一个协程在执行逻辑的时候,另外的协程不执行 ---》锁的机制---》加入互斥锁
互斥锁
package main
import (
"fmt"
"sync"
)
// 定义一个变量:
var totalNum int
var wg sync.WaitGroup //只定义,无需赋值
// 加入互斥锁
var lock sync.Mutex
func add() {
defer wg.Done()
for i := 0; i < 10000; i++ {
//加锁
lock.Lock()
totalNum = totalNum + 1
//解锁
lock.Unlock()
}
}
func sub() {
defer wg.Done()
for i := 0; i < 10000; i++ {
//加锁
lock.Lock()
totalNum = totalNum - 1
//解锁
lock.Unlock()
}
}
func main() {
wg.Add(2)
go add()
go sub()
wg.Wait()
fmt.Println(totalNum)
}
读写锁
只读的时候,同时执行
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup //只定义,无需赋值
// 加入读写锁
var lock sync.RWMutex
func read() {
defer wg.Done()
lock.RLock() //如果只是读数据,那么这个锁不产生影响,但是如果读写同时发生的时候,就会有影响
fmt.Println("开始读取数据")
time.Sleep(time.Second)
fmt.Println("读取数据成功")
lock.RUnlock()
}
func write() {
defer wg.Done()
lock.Lock()
fmt.Println("开始修改数据")
time.Sleep(time.Second * 10)
fmt.Println("修改数据成功")
lock.Unlock()
}
func main() {
wg.Add(6)
//启动协程 --->读多写少
for i := 0; i < 5; i++ {
go read()
}
go write()
wg.Wait()
}
如果把go write()写给注释了,你会看到,读没有任何的影响
有读有写,在写的过程中,锁生效,但是读可以并发读,没有影响