看下面一段代码

package main

import (
    "fmt"
    "sync"
    "time"
)

type Foo struct {
    sync.RWMutex
    m map[int]int
}

func (f Foo) PointerMethod(i int) {
    f.RWMutex.Lock()
    f.m[i] = i
    f.RWMutex.Unlock()
}

func (f Foo) ValueMethod(i int) {
    f.RWMutex.Lock()
    fmt.Println(f.m[i])
    f.RWMutex.Unlock()
}

func main() {
    f1 := Foo{
        m: make(map[int]int, 0),
    }
    for i := 0; i < 100; i++ {
        go f1.ValueMethod(i)
        go f1.PointerMethod(i)
    }
    time.Sleep(6 * time.Second)

}

执行的结果是:panic 并发读写了 concurrent map writes


image.png

出现这种问题是因为采用了值对象导致加锁失败,

原因:

如果方法接收者为对象的指针,则会修改原对象,如果方法接收者为对象的值,那么在方法中被操作的是原对象的副本,不会影响原对象

官方也给了建议:

如果接收者是一个包含 sync.Mutex 或类似同步字段的结构,则接收者必须是一个指针以避免复制。


image.png

解决方法

改成指针即可


image.png