
sync.Mutex 是 Go 语言中实现临界区互斥访问的核心同步原语,它通过底层信号量或原子操作保证同一时间仅一个 goroutine 能进入被保护的代码段;多个独立 Mutex 实例可并行工作,互不影响。
`sync.mutex` 是 go 语言中实现临界区互斥访问的核心同步原语,它通过底层信号量或原子操作保证同一时间仅一个 goroutine 能进入被保护的代码段;多个独立 mutex 实例可并行工作,互不影响。
sync.Mutex 的本质是一个独占式锁(mutual exclusion lock),其行为严格遵循“一锁一持”原则:当某个 goroutine 调用 Lock() 成功后,该 Mutex 即处于锁定状态;此后任何其他 goroutine 对同一 Mutex 实例调用 Lock() 都将被阻塞,直到持有者调用 Unlock() 释放锁。这种阻塞是协作式的、无自旋的,由 Go 运行时调度器高效管理,不会浪费 CPU。
关键点在于:Mutex 的作用域由其实例决定,而非变量名或逻辑用途。也就是说:
- ✅ 单个 sync.Mutex 实例(如 var mu sync.Mutex)全局唯一,所有使用它的代码块共享同一把锁 —— 无论这些代码逻辑是否相关,只要共用同一个 Mutex 实例,就会串行执行;
- ✅ 多个独立 Mutex 实例(如 mu1 和 mu2)彼此完全隔离,可被不同 goroutine 同时锁定,实现真正的并发执行。
以下示例清晰展示了这一机制:
package main
import (
"fmt"
"sync"
"time"
)
var mu sync.Mutex // 共享锁:code1 和 code2 若共用它,则必然串行
var mu1 sync.Mutex // 独立锁:专用于 code2
var wg sync.WaitGroup
func code1() {
mu.Lock()
defer mu.Unlock()
fmt.Println("Entering code1")
time.Sleep(1 * time.Second)
fmt.Println("Exiting code1")
}
func code2() {
mu1.Lock()
defer mu1.Unlock()
fmt.Println("Entering code2")
time.Sleep(1 * time.Second)
fmt.Println("Exiting code2")
}
func main() {
wg.Add(2)
go func() { code1(); wg.Done() }()
go func() { code2(); wg.Done() }()
wg.Wait()
}
运行输出类似:
Entering code2 Entering code1 Exiting code2 Exiting code1
说明两个 goroutine 几乎同时进入各自加锁区域 —— 因为 mu 和 mu1 是两个独立对象,互不干扰。
⚠️ 注意事项:
- 必须成对使用 Lock()/Unlock(),推荐用 defer mu.Unlock() 确保异常路径下仍能释放锁;
- 切勿复制已使用的 Mutex(如作为结构体字段赋值或传参时未取地址),否则会丢失锁状态,引发竞态;
- Mutex 仅解决“访问互斥”,不提供内存可见性保障(但 Go 的 sync 包已隐式满足顺序一致性,无需额外 volatile);
- 对高频短临界区,可考虑 sync.RWMutex 或无锁编程(如 atomic),但切忌过早优化。
总结:sync.Mutex 是轻量、可靠且语义明确的同步工具。合理设计锁粒度(例如为不同资源分配独立 Mutex)是构建高性能并发程序的关键前提。











