本文节选翻译自https://go101.org/article/channel-use-cases.html

Go语言:使用Channel实现互斥锁

channel可以被用来实现互斥锁,虽然这样的实现没有sync库中的Mutex效率高。

对于一个缓冲区大小为1的channel,可以有以下两种方式实现互斥锁:

  1. 通过发送数据加锁,通过接收数据解锁

  2. 通过接收数据加锁,通过发送数据解锁

以下是使用第一种方式的一个例子:

package main

import "fmt"

func main() {
    // 缓冲区长度必须为1。
    mutex := make(chan struct{}, 1)

    counter := 0
    increase := func() {
        mutex <- struct{}{} // 加锁
        counter++
        <-mutex // 解锁
    }

    increase1000 := func(done chan<- struct{}) {
        for i := 0; i < 1000; i++ {
            increase()
        }
        done <- struct{}{}
    }

    done := make(chan struct{})
    go increase1000(done)
    go increase1000(done)
    <-done; <-done
    fmt.Println(counter) // 2000
}

如果想用第二种方式,只需要对上述代码稍作修改:

...
func main() {
    mutex := make(chan struct{}, 1)
    mutex <- struct{}{} // 这行必须有。

    counter := 0
    increase := func() {
        <-mutex // 加锁
        counter++
        mutex <- struct{}{} // 解锁
    }
...