sync.Mutex
是 Go 语言标准库 sync
包中提供的互斥锁(Mutual Exclusion Lock)类型,用于在并发编程中保护共享资源的访问,避免多个 goroutine 同时修改数据导致的竞态条件(Race Condition)。以下是关于 sync.Mutex
的详细说明和使用示例:
1. 核心特性
- 互斥锁:同一时刻只有一个 goroutine 能持有锁,其他 goroutine 必须等待锁释放。
- 零值可用:无需初始化即可直接使用(如
var mu sync.Mutex
)。 - 不可重入:同一个 goroutine 重复加锁会导致死锁(与某些语言的可重入锁不同)。
2. 基本方法
type Mutex struct {
// 内部状态字段(对用户透明)
}
func (m *Mutex) Lock() // 加锁(阻塞直到获取锁)
func (m *Mutex) Unlock() // 解锁(必须在Lock后调用)
3. 使用示例
示例1:保护共享变量
package main
import (
"fmt"
"sync"
)
var (
counter int
mu sync.Mutex
wg sync.WaitGroup
)
func increment() {
defer wg.Done()
mu.Lock() // 加锁
counter++ // 操作共享变量
mu.Unlock() // 解锁
}
func main() {
for i :=0; i <1000; i++ {
wg.Add(1)
go increment()
}
wg.Wait()
fmt.Println("Counter:", counter) // 输出: Counter:1000 (无竞态)
}
示例2:结合 defer 确保解锁
func safeWrite(data map[string]int, key string, value int) {
var mu sync.Mutex
mu.Lock()
defer mu.Unlock() // defer保证即使发生panic也能解锁
data[key] = value
}
4. 注意事项
避免死锁:
- Unlock()必须和Lock()成对出现。
- 不可在未Lock时调用Unlock(会触发panic)。
var mu sync.Mutex mu.Unlock() // panic: unlock of unlocked mutex
性能考虑:
- Mutex有一定开销,高并发场景下可考虑
sync.RWMutex
(读写分离锁)。 - 减少临界区代码量(锁定时间越短越好)。
- Mutex有一定开销,高并发场景下可考虑
非递归锁:
func deadlockExample() { var mu sync.Mutex mu.Lock() mu.Lock() // fatal error: all goroutines are asleep - deadlock! }
5. vs Channel
- 适用场景对比:
| 场景 | 推荐方式 |
|————————|——————|
|保护简单共享变量 |
sync.Mutex
| |协调多阶段复杂任务 |channel
|
6. RWMutex扩展
如果需要更高效率的读多写少场景,可以使用 sync.RWMutex
:
var rwMu sync.RWMutoex
//读操作(允许多个goroutine同时读)
rwMu.RLock()
defer rwMu.RUnlock()
//写操作(独占)
rwMu.Lock()
defer rwMu.Unlock()
通过合理使用 sync.Mutex
,可以确保 Go 并发程序的数据安全性。建议结合 go vet
或竞态检测工具(-race
)验证代码正确性。
内容由零声教学AI助手提供,问题来源于学员提问