Skip to content

Go CAS比较并交换操作 - Golang原子操作详解

CAS(Compare-And-Swap)是实现无锁并发的核心原语。掌握CAS操作对于编写高性能并发代码至关重要。

📋 CAS核心概念

CAS操作原理

CAS是一种原子操作,包含三个操作数:内存位置V、预期值A和新值B。只有当V的值等于A时,才会将V更新为B。

go
package main

import (
    "fmt"
    "sync"
    "sync/atomic"
    "time"
)

func main() {
    fmt.Println("=== Go CAS比较并交换操作 ===")
    
    // 1. 基础CAS操作
    fmt.Printf("\n--- 基础CAS操作 ---\n")
    
    var value int32 = 100
    fmt.Printf("初始值: %d\n", value)
    
    // CAS操作:如果值为100,则更新为200
    swapped := atomic.CompareAndSwapInt32(&value, 100, 200)
    fmt.Printf("CAS(100->200): %t, 当前值: %d\n", swapped, value)
    
    // 再次CAS:预期值不匹配,不会更新
    swapped = atomic.CompareAndSwapInt32(&value, 100, 300)
    fmt.Printf("CAS(100->300): %t, 当前值: %d\n", swapped, value)
    
    // 2. 无锁计数器
    fmt.Printf("\n--- 无锁计数器 ---\n")
    
    type LockFreeCounter struct {
        value int64
    }
    
    func (c *LockFreeCounter) Increment() int64 {
        for {
            old := atomic.LoadInt64(&c.value)
            new := old + 1
            if atomic.CompareAndSwapInt64(&c.value, old, new) {
                return new
            }
            // CAS失败,重试
        }
    }
    
    func (c *LockFreeCounter) Get() int64 {
        return atomic.LoadInt64(&c.value)
    }
    
    counter := &LockFreeCounter{}
    var wg sync.WaitGroup
    
    // 并发增加
    goroutines := 100
    increments := 1000
    
    start := time.Now()
    for i := 0; i < goroutines; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for j := 0; j < increments; j++ {
                counter.Increment()
            }
        }()
    }
    wg.Wait()
    
    elapsed := time.Since(start)
    expected := int64(goroutines * increments)
    actual := counter.Get()
    
    fmt.Printf("期望值: %d\n", expected)
    fmt.Printf("实际值: %d\n", actual)
    fmt.Printf("正确性: %t\n", expected == actual)
    fmt.Printf("耗时: %v\n", elapsed)
    
    // 3. 无锁栈
    fmt.Printf("\n--- 无锁栈 ---\n")
    
    type LockFreeStack struct {
        head unsafe.Pointer
    }
    
    type node struct {
        value int
        next  unsafe.Pointer
    }
    
    func NewLockFreeStack() *LockFreeStack {
        return &LockFreeStack{}
    }
    
    func (s *LockFreeStack) Push(v int) {
        newNode := &node{value: v}
        for {
            oldHead := atomic.LoadPointer(&s.head)
            newNode.next = oldHead
            if atomic.CompareAndSwapPointer(&s.head, oldHead, unsafe.Pointer(newNode)) {
                return
            }
        }
    }
    
    func (s *LockFreeStack) Pop() (int, bool) {
        for {
            oldHead := atomic.LoadPointer(&s.head)
            if oldHead == nil {
                return 0, false
            }
            
            headNode := (*node)(oldHead)
            newHead := headNode.next
            
            if atomic.CompareAndSwapPointer(&s.head, oldHead, newHead) {
                return headNode.value, true
            }
        }
    }
    
    stack := NewLockFreeStack()
    
    // 并发Push
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(val int) {
            defer wg.Done()
            stack.Push(val)
        }(i)
    }
    wg.Wait()
    
    // Pop所有元素
    fmt.Printf("Pop元素: ")
    for {
        val, ok := stack.Pop()
        if !ok {
            break
        }
        fmt.Printf("%d ", val)
    }
    fmt.Println()
    
    // 4. 性能对比
    fmt.Printf("\n--- 性能对比:CAS vs Mutex ---\n")
    
    iterations := 1000000
    
    // CAS版本
    var casCounter int64
    start = time.Now()
    for i := 0; i < iterations; i++ {
        atomic.AddInt64(&casCounter, 1)
    }
    casTime := time.Since(start)
    
    // Mutex版本
    var mutexCounter int64
    var mu sync.Mutex
    start = time.Now()
    for i := 0; i < iterations; i++ {
        mu.Lock()
        mutexCounter++
        mu.Unlock()
    }
    mutexTime := time.Since(start)
    
    fmt.Printf("CAS版本: %v\n", casTime)
    fmt.Printf("Mutex版本: %v\n", mutexTime)
    fmt.Printf("性能提升: %.2fx\n", float64(mutexTime)/float64(casTime))
    
    fmt.Printf("\n🎯 CAS使用建议:\n")
    fmt.Printf("1. 适用于简单的原子更新操作\n")
    fmt.Printf("2. 高竞争下可能频繁重试\n")
    fmt.Printf("3. 无锁不等于无等待\n")
    fmt.Printf("4. 复杂逻辑建议使用Mutex\n")
    fmt.Printf("5. 注意ABA问题\n")
    
    fmt.Printf("\n📋 常用原子操作:\n")
    fmt.Printf("- atomic.CompareAndSwapInt32/64\n")
    fmt.Printf("- atomic.CompareAndSwapPointer\n")
    fmt.Printf("- atomic.AddInt32/64\n")
    fmt.Printf("- atomic.LoadInt32/64\n")
    fmt.Printf("- atomic.StoreInt32/64\n")
}

import "unsafe"

🎯 核心知识点总结

CAS操作特点

  1. 原子性: 操作不可分割,要么成功要么失败
  2. 无锁: 不需要互斥锁,避免了锁开销
  3. 重试机制: 失败时需要重试直到成功
  4. 适用场景: 简单的原子更新操作

无锁数据结构

  1. 无锁计数器: 使用CAS实现线程安全的计数
  2. 无锁栈: 基于CAS的并发栈实现
  3. 无锁队列: 更复杂的无锁数据结构
  4. 性能优势: 在低竞争下性能优于锁

注意事项

  1. ABA问题: 值可能被修改后又改回
  2. 重试开销: 高竞争下重试次数多
  3. 适用范围: 不是所有场景都适合CAS
  4. 正确性: 确保CAS循环的正确性

性能对比

  1. 低竞争: CAS显著优于Mutex
  2. 高竞争: Mutex可能更优
  3. 简单操作: CAS是首选
  4. 复杂临界区: 建议使用Mutex

🔍 面试准备建议

  1. 原理理解: 深入理解CAS的硬件实现
  2. 应用场景: 掌握何时使用CAS
  3. 性能分析: 了解CAS的性能特征
  4. 问题处理: 理解ABA等常见问题
  5. 实践经验: 积累无锁编程经验

正在精进