看下面一段代码
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
出现这种问题是因为采用了值对象导致加锁失败,
原因:
如果方法接收者为对象的指针,则会修改原对象,如果方法接收者为对象的值,那么在方法中被操作的是原对象的副本,不会影响原对象
官方也给了建议:
如果接收者是一个包含 sync.Mutex 或类似同步字段的结构,则接收者必须是一个指针以避免复制。
解决方法
改成指针即可