flyfei

同步原语(sync.Mutex互斥锁、sync.WaitGroup等待组、sync.RWMutex读写锁)

1. 语法讲解

为什么需要同步原语? 在并发编程中,多个goroutine同时访问共享资源时会产生竞态条件,导致数据不一致。

sync.Mutex(互斥锁)

sync.RWMutex(读写锁)

sync.WaitGroup(等待组)

var wg sync.WaitGroup

func main() {
    for i := 0; i < 3; i++ {
        wg.Add(1)        // 计数器+1
        go worker(i)
    }
    wg.Wait()           // 等待所有goroutine完成
}

2. 应用场景

Mutex适用场景

WaitGroup适用场景

RWMutex适用场景

3. 编程实例

电商秒杀库存管理系统

package main

import (
    "fmt"
    "sync"
    "time"
)

type Inventory struct {
    stock    int              // 库存数量
    rwMutex  sync.RWMutex     // 保护库存
}

// 查询库存(使用读写锁的读锁)
func (inv *Inventory) getStock() int {
    inv.rwMutex.RLock()
    defer inv.rwMutex.RUnlock()
    return inv.stock
}

// 扣减库存(使用互斥锁和读写锁的写锁)
func (inv *Inventory) deductStock(userID int, quantity int) bool {
    // 先检查库存(读锁)
    inv.rwMutex.Lock()
    defer inv.rwMutex.Unlock()
	
    // 检查,防止超卖
    if inv.stock < quantity {
        fmt.Printf("用户%d: 库存不足,扣减失败\n", userID)
        return false
    }
    
    inv.stock -= quantity
    fmt.Printf("用户%d: 成功购买%d件,剩余库存%d\n", userID, quantity, inv.stock)
    return true
}

func main() {
    inventory := &Inventory{stock: 10} // 初始库存10件
    
    var wg sync.WaitGroup
    
    // 模拟100个用户同时抢购
    for i := 1; i <= 100; i++ {
        wg.Add(1)
        go func(userID int) {
            defer wg.Done()
            inventory.deductStock(userID, 1)
        }(i)
    }
    
    wg.Wait()
    fmt.Printf("最终库存: %d\n", inventory.getStock())
}

4. 其他用法

原子操作替代简单锁

import "sync/atomic"

type Counter struct {
    value int64
}

func (c *Counter) Increment() {
    atomic.AddInt64(&c.value, 1) // 比mutex性能更好
}

func (c *Counter) Decrement() {
    atomic.AddInt64(&c.value, -1) 
}

func (c *Counter) Value() int64 {
    return atomic.LoadInt64(&c.value)
}

func main() {
	var counter Counter
    var wg sync.WaitGroup
  
    // 模拟100个用户同时点赞
    for i := 1; i <= 100; i++ {
      wg.Add(1)
      go func() {
          defer wg.Done()
          counter.Increment()
      }()
    }

    // 模拟10个用户取消点赞
    for i := 1; i <= 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            counter.Decrement()
        }()
    }
  
    wg.Wait()
}

5. 课时总结