为什么需要同步原语? 在并发编程中,多个goroutine同时访问共享资源时会产生竞态条件,导致数据不一致。
sync.Mutex(互斥锁)
Lock() 和 Unlock()sync.RWMutex(读写锁)
RLock() / RUnlock()(共享锁)Lock() / Unlock()(互斥锁)sync.WaitGroup(等待组)
Add()、Done()、Wait()var wg sync.WaitGroup
func main() {
for i := 0; i < 3; i++ {
wg.Add(1) // 计数器+1
go worker(i)
}
wg.Wait() // 等待所有goroutine完成
}
Mutex适用场景:
WaitGroup适用场景:
RWMutex适用场景:
电商秒杀库存管理系统:
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())
}
原子操作替代简单锁:
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()
}
WaitGroup等待组:协调多个goroutine的完成状态