MST
星途 面试题库

面试题:Go中Mutex和RWMutex的使用场景区别

请阐述在Go语言里,Mutex(互斥锁)和RWMutex(读写互斥锁)分别适用于哪些场景,并举例说明如何使用它们来保护共享资源。
41.1万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

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 是一个 RWMutexread 函数使用 rwmu.RLock() 进行读锁定,允许多个读操作同时进行;write 函数使用 rwmu.Lock() 进行写锁定,保证写操作时其他读写操作无法进行,从而保护 data 这个共享资源。