MST

星途 面试题库

面试题:Go中RWMutex读锁和写锁的区别及应用场景

在Go语言里,RWMutex提供了读写锁机制。请详细阐述读锁(RLock)和写锁(Lock)在功能上的区别,并且分别举例说明它们适用于哪些实际的应用场景。
20.7万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

读锁(RLock)和写锁(Lock)功能区别

  1. 读锁(RLock)
    • 允许多个读操作同时进行,因为读操作不会修改共享资源,所以多个读操作并发执行不会产生数据不一致问题。
    • 当有写锁(Lock)被持有,读锁无法获取,直到写锁被释放。这是为了保证写操作的原子性和数据一致性,避免写操作过程中数据被读取到不一致状态。
  2. 写锁(Lock)
    • 写锁是排他锁,当一个写锁被持有,其他任何读锁或写锁都无法获取,直到该写锁被释放。这是为了确保在写操作过程中,共享资源不会被其他读写操作干扰,保证写操作的原子性和数据一致性。

实际应用场景举例

  1. 读锁(RLock)适用场景
    • 缓存读取:例如一个应用中有一个缓存,存储了一些配置信息。多个不同的模块可能同时需要读取这些配置信息,由于读取操作不会修改缓存数据,所以可以使用读锁。这样多个读操作可以并发进行,提高读取效率。
    package main
    
    import (
        "fmt"
        "sync"
    )
    
    var (
        configCache map[string]string
        rwMutex     sync.RWMutex
    )
    
    func readConfig(key string) string {
        rwMutex.RLock()
        defer rwMutex.RUnlock()
        return configCache[key]
    }
    
    func main() {
        configCache = make(map[string]string)
        configCache["server_addr"] = "127.0.0.1:8080"
    
        var wg sync.WaitGroup
        for i := 0; i < 10; i++ {
            wg.Add(1)
            go func() {
                defer wg.Done()
                fmt.Println(readConfig("server_addr"))
            }()
        }
        wg.Wait()
    }
    
  2. 写锁(Lock)适用场景
    • 数据更新:假设一个银行账户系统,账户余额是共享资源。当进行存款或取款操作(写操作)时,为了保证余额数据的一致性,需要使用写锁。只有一个写操作可以进行,避免多个写操作同时修改余额导致数据错误。
    package main
    
    import (
        "fmt"
        "sync"
    )
    
    type BankAccount struct {
        balance int
        rwMutex sync.RWMutex
    }
    
    func (ba *BankAccount) deposit(amount int) {
        ba.rwMutex.Lock()
        defer ba.rwMutex.Unlock()
        ba.balance += amount
    }
    
    func (ba *BankAccount) getBalance() int {
        ba.rwMutex.RLock()
        defer ba.rwMutex.RUnlock()
        return ba.balance
    }
    
    func main() {
        account := BankAccount{balance: 100}
    
        var wg sync.WaitGroup
        for i := 0; i < 5; i++ {
            wg.Add(1)
            go func() {
                defer wg.Done()
                account.deposit(10)
            }()
        }
        wg.Wait()
        fmt.Println("Final balance:", account.getBalance())
    }