面试题答案
一键面试读锁(RLock)和写锁(Lock)功能区别
- 读锁(RLock):
- 允许多个读操作同时进行,因为读操作不会修改共享资源,所以多个读操作并发执行不会产生数据不一致问题。
- 当有写锁(Lock)被持有,读锁无法获取,直到写锁被释放。这是为了保证写操作的原子性和数据一致性,避免写操作过程中数据被读取到不一致状态。
- 写锁(Lock):
- 写锁是排他锁,当一个写锁被持有,其他任何读锁或写锁都无法获取,直到该写锁被释放。这是为了确保在写操作过程中,共享资源不会被其他读写操作干扰,保证写操作的原子性和数据一致性。
实际应用场景举例
- 读锁(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() }
- 写锁(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()) }