Mutex 互斥锁相关的介绍使用
1. 互斥锁的定义
互斥锁:是一种同步机制,用于在存在许多执行线程的环境中强制限制对资源的访问。锁旨在实施互斥 并发控制策略。
我们来看一个示意图:
没有锁的时候,A、B、C同时争抢资源E,像打架似的谁也不让谁,有锁了以后,只有A拥有该资源,B/C只能在外面等待
索被释放
2. 互斥锁的使用
想象我们有1w个商品券发给同时发给1w个人,每个人都会得到一张商品券,每张商品券核销码都不一样,且只能核销一次
看如下简化代码:
package main
import (
"fmt"
"sync"
)
type GoodsNum struct {
value int
lock sync.Mutex
}
func decrGoodNum(clientId int , good *GoodsNum,group *sync.WaitGroup) {
good.lock.Lock()
defer func() {
good.lock.Unlock()
group.Done()
}()
good.value--
fmt.Println("client ",clientId," get the good and good num left ",good.value)
}
func main() {
var waitGroup sync.WaitGroup
l := sync.Mutex{}
good := GoodsNum{
value:10000,
lock:l,
}
start := time.Now().UnixNano()
waitGroup.Add(10000)
for i := 1 ; i<= 10000 ; i++ {
go decrGoodNum(i,&good,&waitGroup)
}
waitGroup.Wait()
end := time.Now().UnixNano()
fmt.Println("exec complete good num left ",good.value)
fmt.Println("cast time ",end - start,"ns")
}
不加锁的情况下,我们注释掉 0/1/2/3/4 这五处代码,然后执行,结果截图如下:
然后我们打开这五处注释,执行,结果截图如下
然后我们发现,我们没有加锁时,居然多出来 12 张没有发完,这就是之前提到的原子性操作,多个线程同时拿到同一个资源时,同时操作会导致结果的不确定性,然后我们加了互斥锁以后,结果始终是0。
互斥锁对性能稍微有点开销,所以我们尽可能的将需要加锁的代码减少到最少。
最佳实践:将要锁住的代码片段放入匿名函数
go func(){
lock.lock()
defer lock.unlock()
}()
|
请发表评论