GO语言培训之什么是互斥锁?
老男孩IT教育
技术博客
2021年2月5日 14:14
Go语言的sync包中实现了两种锁 Mutex (互斥锁)和 RWMutex (读写锁),其中 RWMutex 是基于 Mutex 实现的,只读锁的实现使用类似引用计数器的功能。
Go语言的sync包中实现了两种锁 Mutex (互斥锁)和 RWMutex (读写锁),其中 RWMutex 是基于 Mutex 实现的,只读锁的实现使用类似引用计数器的功能。
互斥锁
Mutex 是互斥锁,有 Lock()加锁、Unlock()解锁两个方法,使用Lock()加锁后,便不能再次对其进行加锁,直到利用 Unlock()解锁对其解锁后才能再次加锁。适用于读写不确定场景,即读写次数没有明显的区别,并且只允许只有一个读或者写的场景,所以该锁也叫做全局锁。
func (m *Mutex) Lock()
Lock方法锁住m,如果m已经加锁,则阻塞直到m解锁。
func (m *Mutex) Unlock()
Unlock方法解锁m,如果m未加锁会导致运行时错误。锁和线程无关,可以由不同的线程加锁和解锁。
互斥锁应用
只要有两个goroutine并发访问同一变量,且至少其中的一个是写操作的时候就会发生数据竞争。数据竞争会在两个以上的goroutine并发访问相同的变量且至少其中一个为写操作时发生。
允许多个goroutine访问变量,但是同一时间只允许一个goroutine访问。我们可以用sync包中的Mutex来实现,保证共享变量不会被并发访问。
实例如下:
package main
import (
"fmt"
"sync"
)
var (
m = make(map[int]int)
Mlock = new(sync.Mutex)
)
func main() {
for i := 0; i < 1000; i++ {
go func(i int) {
// Mlock.Lock()
m[i] = i * i
// Mlock.Unlock()
}(i)
}
// Mlock.Lock()
for k, v := range m {
fmt.Printf("%d * %d = %d\n", k, k, v)
}
// Mlock.Unlock()
}
运行错误:
fatal error: concurrent map writes
将上述代码中的注释打开则程序正常运行。
当Unlock()在Lock()之前使用时便会报错,实例如下:
package main
import (
"fmt"
"sync"
)
func main() {
var MLock *sync.Mutex
MLock = new(sync.Mutex)
MLock.Unlock()
fmt.Println("hello Mutex")
MLock.Lock()
}
运行错误:
panic: sync: unlock of unlocked mutex
当在解锁之前再次进行加锁,便会死锁状态,实例如下:
package main
import (
"fmt"
"sync"
)
func main() {
var MLock *sync.Mutex
MLock = new(sync.Mutex)
MLock.Lock()
fmt.Println("hello Mutex")
MLock.Lock()
}
运行错误:
fatal error: all goroutines are asleep - deadlock!
互斥锁只能锁定一次,当在解锁之前再次进行加锁,便会死锁状态,如果在加锁前解锁,便会报错“panic: sync: unlock of unlocked mutex”。
老男孩教育IT课程,11余年技术沉淀,紧跟技术潮流,10大阶段从入门到专业层层进阶,无论你是否有IT基础,均可轻松学会,成就高薪职业!
推荐阅读:
