面试题答案
一键面试1. 适用场景
- 共享资源访问控制:当多个goroutine需要访问共享资源(如全局变量、共享数据结构等),以避免数据竞争时使用。例如,多个goroutine同时对一个全局计数器进行增减操作。
- 临界区保护:对一段需要独占执行的代码区域(临界区)进行保护,确保同一时间只有一个goroutine能执行该区域代码。
2. 示例
package main
import (
"fmt"
"sync"
)
var (
counter int
mu sync.Mutex
)
func increment(wg *sync.WaitGroup) {
defer wg.Done()
mu.Lock()
counter++
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 counter value:", counter)
}
在上述代码中,多个goroutine同时调用increment
函数对counter
进行增加操作,通过互斥锁mu
确保每次只有一个goroutine能修改counter
,避免数据竞争。
3. 注意事项
- 正确的加锁解锁配对:必须确保在临界区代码前后正确调用
Lock
和Unlock
方法,避免死锁。例如,不要在Lock
之后的代码逻辑中提前返回而没有调用Unlock
。 - 避免嵌套加锁:尽量避免在持有一个互斥锁的情况下再去获取另一个互斥锁,否则可能导致死锁。如果确实需要,要确保加锁顺序的一致性。
- 性能问题:虽然互斥锁能保证数据安全,但频繁的加锁解锁操作会带来性能开销,因此要尽量缩小临界区代码范围,减少加锁时间。