字节笔记本字节笔记本

Go map 为什么不是线程安全的?如何解决?

2023-03-25

Go map 不是线程安全的,需要使用 sync 包中的 Mutex 或 RWMutex 来加锁以防止数据竞争和脏数据,确保并发访问时的数据一致性和正确性。

Go map 不是线程安全的原因是因为在多个 goroutine 并发读写 map 时可能会导致数据竞争和不确定的结果,可能读出来的数据是脏数据。因此,在并发情况下需要加锁来保证 map 的线程安全性。

在 Go 中可以使用 sync 包中的 Mutex 或 RWMutex(读写锁)来保证 map 的线程安全性。使用 Mutex 或 RWMutex 可以在读写 map 时加锁,防止多个 goroutine 并发访问,保证数据的一致性和正确性。

下面是使用 Mutex 来实现线程安全的例子:

var m = make(map[string]int)
var mtx sync.Mutex

func main() {
    go func() {
        for {
            // 加锁
            mtx.Lock()
            m["a"]++
            // 解锁
            mtx.Unlock()
        }
    }()

    go func() {
        for {
            mtx.Lock()
            m["a"]--
            mtx.Unlock()
        }
    }()

    time.Sleep(time.Second)
    fmt.Println(m["a"])
}

在上面的例子中,首先创建了一个包含 string 类型键和 int 类型值的 map,然后定义了一个 Mutex 类型的变量 mtx,用于保护 map 的读写。接着创建了两个 goroutine 分别对 map 中的值进行加减操作,每个 goroutine 中加锁操作能够保证在执行修改操作时不会被其它 goroutine 执行中间插入修改操作,避免了数据竞争和脏数据的问题。最后,等待 goroutine 执行完毕并输出 map 中 "a" 键对应的值。