目录

Golang sync 包底层原理

Go 语言的 sync package 是并发编程的核心。面试和实际开发中的考点通常集中在底层原理、正常/饥饿模式切换、CAS 原子操作以及内存屏障。 以下是 sync 包中 5 个最核心的考点及其 Mermaid 原理图


1. sync.Mutex:正常模式与饥饿模式

考点: 为了防止 Goroutine 被“饿死”,Mutex 会在“正常模式”和“饥饿模式”之间切换。

  • 正常模式: 性能好,新来的 Goroutine 会竞争锁(自旋),可能导致等待队列里的 Goroutine 抢不到锁。
  • 饥饿模式: 公平,锁会直接交给等待队列头部的 Goroutine,新来的不自旋,直接排队。

2. sync.Once:双重检测锁 (DCL)

考点: 保证全局只执行一次。核心是 done 标志位(原子操作)和 Mutex(处理并发请求)。

  • 误区: 不能只用原子操作,因为如果两个协程同时进来,其中一个执行时,另一个必须阻塞等待,否则会拿到一个初始化一半的对象。

3. sync.WaitGroup:计数器与信号量

考点: 如何实现“等待所有任务完成”。底层是一个 64 位的复合变量(Counter + Waiter)和一个信号量。

  • 原理: Add 修改计数器,Wait 检查计数器是否为 0,不为 0 则进入信号量阻塞。

4. sync.Map:读写分离与空间换时间

考点: 为什么在高并发读时性能好?因为它用了两个 Map:read(原子只读,不加锁)和 dirty(加锁写)。

  • Miss 升级:read 频繁未命中(Miss)时,会将 dirty 提升为 read

5. sync.Pool:GC 影响与 Per-P 缓存

考点: 用于对象复用,减轻 GC 压力。

  • 核心: 每一个调度器 P 都有自己的 localPool,优先访问本地,避免锁竞争。
  • 注意: sync.Pool 里的对象会在 GC 时被清理,不能当作长期缓存(如 Redis)使用。

总结:

  1. Mutex: 关注自旋饥饿模式
  2. Once: 关注双重检查锁
  3. WaitGroup: 关注原子计数器信号量唤醒
  4. Map: 关注读写分离Dirty 提升机制
  5. Pool: 关注Per-P 缓存GC 清理逻辑