MST

星途 面试题库

面试题:Go 中互斥锁(Mutex)与读写锁(RWMutex)的应用场景区别

在 Go 语言中,互斥锁(Mutex)和读写锁(RWMutex)是常用的同步原语。请阐述它们各自的应用场景,并举例说明在什么样的业务场景下应该选择使用互斥锁,什么样的场景下应该选择读写锁。
47.9万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

互斥锁(Mutex)应用场景

互斥锁主要用于保护共享资源,确保同一时间只有一个 goroutine 能够访问该资源,防止数据竞争。适用于读写操作都可能修改共享资源状态的场景。

示例业务场景:银行账户转账操作。多个 goroutine 可能同时进行转账操作,需要保证账户余额在修改时的一致性。

package main

import (
    "fmt"
    "sync"
)

type BankAccount struct {
    balance int
    mutex   sync.Mutex
}

func (b *BankAccount) Transfer(amount int) {
    b.mutex.Lock()
    defer b.mutex.Unlock()
    b.balance += amount
}

func main() {
    account := BankAccount{balance: 100}
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            account.Transfer(10)
        }()
    }
    wg.Wait()
    fmt.Println("Final balance:", account.balance)
}

读写锁(RWMutex)应用场景

读写锁适用于读操作远多于写操作的场景。它允许多个 goroutine 同时进行读操作,但写操作时会独占资源,阻止其他读写操作。

示例业务场景:缓存数据读取。大量 goroutine 频繁读取缓存数据,偶尔有 goroutine 更新缓存数据。

package main

import (
    "fmt"
    "sync"
)

type Cache struct {
    data  map[string]interface{}
    rwmu  sync.RWMutex
}

func (c *Cache) Read(key string) interface{} {
    c.rwmu.RLock()
    defer c.rwmu.RUnlock()
    return c.data[key]
}

func (c *Cache) Write(key string, value interface{}) {
    c.rwmu.Lock()
    defer c.rwmu.Unlock()
    if c.data == nil {
        c.data = make(map[string]interface{})
    }
    c.data[key] = value
}

func main() {
    cache := Cache{}
    var wg sync.WaitGroup
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            cache.Write(fmt.Sprintf("key%d", id), id)
        }(i)
    }
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            result := cache.Read(fmt.Sprintf("key%d", id%5))
            fmt.Printf("goroutine %d read: %v\n", id, result)
        }(i)
    }
    wg.Wait()
}