面试题答案
一键面试Mutex(互斥锁)适用场景
- 适用于读写操作频率相近,或者写操作较多的场景。当对共享资源的读写操作都可能改变其状态时,为避免数据竞争,需要使用Mutex保证同一时刻只有一个 goroutine 能访问共享资源。
Mutex 使用示例
package main
import (
"fmt"
"sync"
)
var (
count int
mu sync.Mutex
)
func increment(wg *sync.WaitGroup) {
defer wg.Done()
mu.Lock()
count++
mu.Unlock()
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go increment(&wg)
}
wg.Wait()
fmt.Println("Final count:", count)
}
在上述代码中,mu
是一个 Mutex
,在 increment
函数中,每次对共享变量 count
进行自增操作前,先通过 mu.Lock()
加锁,操作完成后通过 mu.Unlock()
解锁,以此保护 count
这个共享资源。
RWMutex(读写互斥锁)适用场景
- 适用于读操作远远多于写操作的场景。因为读操作不会改变共享资源的状态,多个 goroutine 可以同时进行读操作,而写操作则需要独占访问以防止数据不一致。RWMutex 允许在没有写操作时,多个读操作同时进行,提高并发性能。
RWMutex 使用示例
package main
import (
"fmt"
"sync"
)
var (
data = make(map[string]string)
rwmu sync.RWMutex
)
func read(key string, wg *sync.WaitGroup) {
defer wg.Done()
rwmu.RLock()
value := data[key]
fmt.Printf("Read key %s, value: %s\n", key, value)
rwmu.RUnlock()
}
func write(key, value string, wg *sync.WaitGroup) {
defer wg.Done()
rwmu.Lock()
data[key] = value
fmt.Printf("Write key %s, value: %s\n", key, value)
rwmu.Unlock()
}
func main() {
var wg sync.WaitGroup
// 写操作
wg.Add(1)
go write("name", "John", &wg)
// 读操作
for i := 0; i < 3; i++ {
wg.Add(1)
go read("name", &wg)
}
wg.Wait()
}
在上述代码中,rwmu
是一个 RWMutex
。read
函数使用 rwmu.RLock()
进行读锁定,允许多个读操作同时进行;write
函数使用 rwmu.Lock()
进行写锁定,保证写操作时其他读写操作无法进行,从而保护 data
这个共享资源。