Golang Mutex(互斥锁)讲解
🏗 什么是 Mutex?
Mutex 全称是 Mutual Exclusion(互斥)。 在并发编程中,它是一种锁机制, 用来: ✅ 保护共享资源, ✅ 保证同一时间 只有一个 goroutine 能访问资源, ✅ 避免竞态条件(race condition)。
简单说:
当多个 goroutine 要修改同一块数据时,必须用锁,否则数据可能混乱。
🌟 Mutex 在 Go 里的位置
Go 的 sync
包提供了 sync.Mutex
,用法简单:
var mu sync.Mutex
它有两个核心方法:
方法 | 作用 |
---|---|
mu.Lock() | 加锁(获得互斥权) |
mu.Unlock() | 解锁(释放互斥权) |
🚦 什么时候需要 Mutex?
当你有:
-
多个 goroutine 读写共享变量
-
多个 goroutine 修改共享 map、slice、struct
⚠ 注意:只读不写的场景可以用 RWMutex 或不加锁。
🏹 Mutex 的基本用法
import ( "fmt" "sync" ) var ( mu sync.Mutex counter int ) func increment() { mu.Lock() counter++ mu.Unlock() }
这里: ✅ mu.Lock()
进入临界区(只允许一个 goroutine 进入) ✅ counter++
是临界操作 ✅ mu.Unlock()
离开临界区(让其他 goroutine 进来)
⚙ 完整示例:多个 goroutine 并发加计数器
package main import ( "fmt" "sync" ) var ( counter int mu sync.Mutex wg sync.WaitGroup ) func main() { for i := 0; i < 1000; i++ { wg.Add(1) go func() { mu.Lock() counter++ mu.Unlock() wg.Done() }() } wg.Wait() fmt.Println("Final counter:", counter) }
说明:
-
启动 1000 个 goroutine,每个 +1
-
用
mu
保证同时只有一个 goroutine 在修改counter
-
最终输出 肯定是 1000(不用锁就不保证了)
🛡 为什么不用锁会出错?
因为 counter++
其实是:
-
读 counter
-
+1
-
写回 counter
多个 goroutine 并发做这个,可能出现:
-
都读到旧值(比如 0)
-
都写回新值(比如 1),但丢失了其他更新
结果:
丢失更新(lost update)
用锁可以强制它们排队,一个一个来。
💥 Mutex 常见坑
✅ 1️⃣ 忘记 Unlock
mu.Lock() // 出错 return 或 panic,没有解锁
👉 最好用 defer
:
mu.Lock() defer mu.Unlock()
✅ 2️⃣ 死锁 两个 goroutine 互相等对方解锁,谁也走不动。
mu1.Lock() mu2.Lock() // ... 业务 mu2.Unlock() mu1.Unlock()
如果反过来:
mu2.Lock() mu1.Lock()
就可能互相卡住。
👉 建议:锁顺序一致
✅ 3️⃣ 性能过低 所有 goroutine 都串行化,等同于单线程。
👉 如果只是读,考虑用:
-
sync.RWMutex
:允许多个读,写时独占。 -
atomic
包:对于简单数值加减更高效。
🌈 RWMutex 简单对比
类型 | 适用场景 |
---|---|
sync.Mutex | 读写都少,改动大,串行化 |
sync.RWMutex | 多读少写,允许并行读 |
RWMutex 用法:
var rw sync.RWMutex rw.RLock() // 读锁 rw.RUnlock() rw.Lock() // 写锁 rw.Unlock()
🧪 更强用法:带超时或尝试锁(Go 没有)
注意:
-
Go 的
sync.Mutex
没有TryLock()
或带超时的锁。 -
如果需要这些,可以用:
-
sync/atomic
包 -
第三方库(如 github.com/abiosoft/semaphore)
-
自己用
channel
实现控制。
-
📦 总结
核心概念 |
---|
sync.Mutex 提供互斥锁 |
Lock() 加锁,Unlock() 解锁 |
保护共享资源,防止数据竞争 |
用 defer Unlock() 防止忘记解锁 |
多读场景用 RWMutex 更高效 |
注意避免死锁,保持锁顺序一致 |
👉 立即点击链接,开启你的全栈开发之路:Golang全栈开发完整课程