跳转到内容

Go 互斥锁mutex

来自代码酷
Admin留言 | 贡献2025年4月29日 (二) 04:41的版本 (Page creation by admin bot)

(差异) ←上一版本 | 已核准修订 (差异) | 最后版本 (差异) | 下一版本→ (差异)


简介[编辑 | 编辑源代码]

互斥锁(Mutex)是Go语言并发编程中用于保护共享资源的核心同步机制,属于sync包的一部分。当多个goroutine需要访问同一块共享数据时,互斥锁确保同一时间只有一个goroutine能进入临界区(Critical Section),从而避免竞态条件(Race Condition)和数据不一致问题。

数学上,互斥锁实现了对共享资源的互斥访问,可用以下公式表示: MutexLock()Unlock()

基本用法[编辑 | 编辑源代码]

Go的互斥锁通过sync.Mutex类型实现,提供两个关键方法:

  • Lock():获取锁,若锁已被其他goroutine持有,则当前goroutine阻塞
  • Unlock():释放锁,允许其他goroutine获取锁

示例代码[编辑 | 编辑源代码]

package main

import (
	"fmt"
	"sync"
)

var counter int
var mu sync.Mutex

func increment() {
	mu.Lock()         // 加锁
	counter++         // 临界区
	mu.Unlock()       // 解锁
}

func main() {
	var wg sync.WaitGroup
	for i := 0; i < 1000; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			increment()
		}()
	}
	wg.Wait()
	fmt.Println("Final counter:", counter) // 正确输出: 1000
}

输出:

Final counter: 1000

关键点:

  • 不加锁时,多个goroutine同时修改counter会导致结果不确定
  • 使用defer mu.Unlock()是更安全的做法,可避免忘记释放锁

底层原理[编辑 | 编辑源代码]

Go的互斥锁通过组合以下机制实现:

  • 自旋锁:短期等待时循环检查锁状态
  • 等待队列:长期等待的goroutine会被放入队列
  • 原子操作:底层依赖atomic包的CAS(Compare-And-Swap)操作

stateDiagram-v2 [*] --> Unlocked Unlocked --> Locked: Lock()成功 Locked --> Unlocked: Unlock() Locked --> Waiting: Lock()失败 Waiting --> Locked: 被唤醒

高级用法[编辑 | 编辑源代码]

读写锁(RWMutex)[编辑 | 编辑源代码]

当读操作远多于写操作时,sync.RWMutex效率更高:

  • 允许多个读锁同时存在
  • 写锁独占,与任何其他锁互斥
var rwMu sync.RWMutex

func readData() {
	rwMu.RLock()       // 读锁
	defer rwMu.RUnlock()
	// 读取共享数据
}

func writeData() {
	rwMu.Lock()        // 写锁
	defer rwMu.Unlock()
	// 修改共享数据
}

实际案例[编辑 | 编辑源代码]

银行账户转账[编辑 | 编辑源代码]

type Account struct {
	balance int
	mu      sync.Mutex
}

func (a *Account) Transfer(to *Account, amount int) {
	a.mu.Lock()
	defer a.mu.Unlock()
	
	to.mu.Lock()
	defer to.mu.Unlock()
	
	a.balance -= amount
	to.balance += amount
}

死锁预防技巧: 1. 固定获取锁的顺序(如按账户ID排序) 2. 使用sync.Map替代手动锁管理 3. 设置锁超时(通过select+time.After

性能考量[编辑 | 编辑源代码]

  • 锁粒度:细粒度锁(保护最小必要数据)优于粗粒度锁
  • 锁持续时间:临界区应尽可能短
  • 测量工具:使用go test -benchpprof分析锁竞争
锁性能对比(纳秒/操作)
场景 Mutex RWMutex(读) atomic
无竞争 15-20 25-30 5-10
高竞争 200+ 50(读) / 200+(写) N/A

常见错误[编辑 | 编辑源代码]

  1. 忘记解锁(导致死锁)
  2. 重复解锁(引发panic)
  3. 锁拷贝(值传递会使锁失效)
  4. 嵌套锁(容易导致死锁)

最佳实践[编辑 | 编辑源代码]

1. 使用defer确保解锁 2. 为包含锁的结构体定义String()方法时避免触发锁 3. 考虑使用sync/atomic替代简单计数器 4. 在高并发场景测试锁竞争

页面模块:Message box/ambox.css没有内容。