Golang中的互斥鎖Mutex與讀寫鎖RWMutex詳解
Golang中的sync包實(shí)現(xiàn)了兩種鎖:互斥鎖(Mutex)和讀寫鎖(RWMutex)。
互斥鎖(sync.Mutex)
- 使用Lock方法加鎖,使用Unlock方法解鎖,Golang從1.18新增了TryLock方法,用于嘗試獲取鎖,返回成功或者失??;
- 如果Mutex被一個(gè)goroutine獲取后,其他goroutine只能等到這個(gè)goroutine釋放該Mutex后才能獲取;
- 使用Lock方法加鎖后,不能再次加鎖,直到使用Unlock方法釋放鎖后才能再次加鎖;加鎖之前使用Unlock方法會(huì)導(dǎo)致panic;
- Mutex并不與特定的goroutine相關(guān)聯(lián),一個(gè)goroutine加鎖,也可以使用另一個(gè)goroutine解鎖;
- 在同一個(gè)goroutine中的Mutex解鎖之前再次進(jìn)行加鎖,會(huì)導(dǎo)致死鎖。
互斥鎖的一個(gè)經(jīng)典案例是對(duì)切片進(jìn)行并發(fā)安全的操作,代碼如下:
package main
import (
"fmt"
"sync"
)
var mu sync.Mutex
var slice []int
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
for j := 0; j < 100; j++ {
mu.Lock()
slice = append(slice, j)
mu.Unlock()
}
wg.Done()
}()
}
wg.Wait()
fmt.Println(len(slice))
}
首先定義了一個(gè)長(zhǎng)度為0的slice,并發(fā)地對(duì)其進(jìn)行了1000次append操作。
讀寫鎖(RWMutex)
- RWMutex該鎖可以加多個(gè)讀鎖(RLock)或者一個(gè)寫鎖(Lock),Golang從1.18新增了TryLock和TryRLock方法,分別用于嘗試獲取寫鎖和讀鎖,返回成功或者失敗。
- 讀鎖被占用的情況下會(huì)阻止寫,不會(huì)阻止讀,多個(gè)goroutine可以同時(shí)獲得讀鎖。
- 寫鎖會(huì)阻止其他goroutine對(duì)寫鎖和讀鎖的獲取。
看一個(gè)代碼示例:
package main
import (
"log"
"sync"
)
var mu sync.RWMutex
var m map[string]string
func main() {
m = make(map[string]string)
mu.Lock()
m["a"] = "A"
mu.Unlock()
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
mu.RLock()
log.Println(m["a"]) // 并發(fā)讀
mu.RUnlock()
wg.Done()
}(i)
}
wg.Wait()
}
首先定義了一個(gè)map,然后對(duì)其進(jìn)行了一次寫操作和10次并發(fā)讀操作。在并發(fā)讀的時(shí)候,使用讀鎖來支持并發(fā)訪問。
小結(jié)
本文講解了互斥鎖和讀寫鎖的特點(diǎn),兩種鎖都可以用于協(xié)調(diào)多個(gè)并發(fā)訪問共享資源的同步機(jī)制。可以看出互斥鎖適用于讀寫不確定,并且只有一個(gè)讀或者寫的場(chǎng)景;讀寫鎖適用于讀多寫少的場(chǎng)景,可以有更高的性能。需要注意的是盡量避免在鎖的范圍內(nèi)進(jìn)行耗時(shí)較長(zhǎng)的操作,以免影響性能。