golang 协程互斥锁


golang 在多协程的情况下,如果多个协程同时操作一个变量,会出现数据不一致的情况,这个时候就需要使用互斥锁来解决这个问题。

互斥锁 (sync.Mutex)

互斥即不可同时运行。即使用了互斥锁的两个代码片段互相排斥,只有其中一个代码片段执行完成后,另一个才能执行。

Go 标准库中提供了 sync.Mutex 互斥锁类型及其两个方法:

Lock 加锁
Unlock 释放锁

代码案例

下面是没有使用锁一个例子情况:

var setMap = make(map[int]bool,0) 

func printOnce(num int) {
  if _, exist := setMap[num]; !exist {
        fmt.Println(num)
    }
    setMap[num] = true
}

func main() {
    for i := 0; i < 10; i++ {
        go printOnce(100)
    }
    time.Sleep(time.Second)
}

运行 go run main.go 会发生什么情况呢?

go run main.go
100
100

多运行几次打印不同的结果, 有时候打印7次,有时候打印10次,有时候还触发 panic,是因为对同一个数据结构的访问冲突了。解决的方法使用 Lock()UnLock() 的方法解决问题

var m sync.Mutex
var setMap = make(map[int]bool, 0)

func printOnce(num int) {
    m.Lock()
    if _, exist := setMap[num]; !exist {
        fmt.Println(num)
    }
    setMap[num] = true
    m.Unlock()

}

func main() {
    for i := 0; i < 10; i++ {
        go printOnce(100)
    }
    time.Sleep(time.Second)
}

运行 go run main.go

go run main.go 
100

注意:

一个互斥锁只能同时被一个 goroutine 锁定,其它 goroutine 就算调用 Lock() 方法也会等待锁的释放。

func main() {
    ch := make(chan struct{}, 2)
    var m sync.Mutex
    go func() {
        m.Lock()
        defer m.Unlock()
        fmt.Println("goroutine1: 大概锁定 2s")
        time.Sleep(time.Second * 2)
        fmt.Println("goroutine1: 锁定结束,准备退出")
        ch <- struct{}{}
    }()

    go func() {
        fmt.Println("goroutine2: 等待解锁")
        m.Lock()
        defer m.Unlock()
        fmt.Println("goroutine2: 锁定结束")
        ch <- struct{}{}
    }()
    // 等待 goroutine 执行结束
    for i := 0; i < 2; i++ {
        <-ch
    }
}

运行 go run main.go

 go run main.go
goroutine1: 大概锁定 2s
goroutine2: 等待解锁
goroutine1: 锁定结束,准备退出
goroutine2: 锁定结束


文章作者: costalong
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 costalong !
评论
  目录
国庆
快乐