在线文档  >   Golang练习   >   互斥锁

在原子计数器这个例子中,我们看到了如何使用原子操作管理简单的计数器状态。
对于更复杂的状态,我们可以使用mutex来安全地访问多个 协程 之间的数据。

package main

import (
    "fmt"
    "sync"
)

// Container保存一个计数器映射;由于我们希望并发地从多个goroutine更新它,
//所以我们添加了Mutex 来同步访问。
//请注意,mutexes 不能被复制,因此如果此 “结构体” 被传递,应该通过指针来完成。
type Container struct {
    mu       sync.Mutex
    counters map[string]int
}

func (c *Container) inc(name string) {
    // 在访问counters之前锁定互斥锁;使用 defer 语句在函数末尾解锁。
    c.mu.Lock()
    defer c.mu.Unlock()
    c.counters[name]++
}

func main() {
    c := Container{
        //请注意,mutex 的零值是可用的,因此不需要在这里初始化。
        counters: map[string]int{"a": 0, "b": 0},
    }

    var wg sync.WaitGroup

    // 此函数在循环中增加命名计数器。
    doIncrement := func(name string, n int) {
        for i := 0; i < n; i++ {
            c.inc(name)
        }
        wg.Done()
    }

    // 并发运行多个协程;请注意,它们都访问相同的`Container`,
    //其中两个访问了同一个计数器。
    wg.Add(3)
    go doIncrement("a", 10000)
    go doIncrement("a", 10000)
    go doIncrement("b", 10000)

    // 等待协程完成
    wg.Wait()
    fmt.Println(c.counters)
}

运行结果如下:

$ go run mutexes.go
map[a:20000 b:10000]

运行该程序显示计数器按预期更新。
接下来,我们将了解如何仅使用 协程 和通道实现相同的状态管理任务。