golang 并发锁的问题
问题代码示例:
package main import ( "fmt" "sync" ) type Data struct { lock sync.Mutex Pojo map[string]string } func main() { list := make([]Data, 3) list[0] = Data{Pojo: make(map[string]string)} list[1] = Data{Pojo: make(map[string]string)} list[2] = Data{Pojo: make(map[string]string)} for i := 0; i < 2000; i++ { go func(index int) { j := index % 3 data1 := list[j] data1.lock.Lock() defer data1.lock.Unlock() data1.Pojo["1"] = "1" }(i) } fmt.Println(list) }
上面这段代码,并发生成2000个协程,修改pojo里面的数据,看似没啥问题,但是会报错
明明已经加锁了,为什么还是报错呢?
原因:data每次从list取出来时,是copy了一份给data1, Pojo是指针类型,多份copy其实操作的是同一份内容, 但lock不是指针类型,操作的是不同的lock,相当于lock并没有生效
解决办法1:把lock改成指针类型
package main import ( "fmt" "sync" ) type Data struct { lock *sync.Mutex Pojo map[string]string } func main() { list := make([]Data, 3) list[0] = Data{Pojo: make(map[string]string), lock: new(sync.Mutex)} list[1] = Data{Pojo: make(map[string]string), lock: new(sync.Mutex)} list[2] = Data{Pojo: make(map[string]string), lock: new(sync.Mutex)} for i := 0; i < 2000; i++ { go func(index int) { j := index % 3 data1 := list[j] data1.lock.Lock() defer data1.lock.Unlock() data1.Pojo["1"] = "1" }(i) } fmt.Println(list) }
解决办法2:把data改成指针类型
package main import ( "fmt" "sync" ) type Data struct { lock sync.Mutex Pojo map[string]string } func main() { list := make([]*Data, 3) list[0] = &Data{Pojo: make(map[string]string)} list[1] = &Data{Pojo: make(map[string]string)} list[2] = &Data{Pojo: make(map[string]string)} for i := 0; i < 2000; i++ { go func(index int) { j := index % 3 data1 := list[j] data1.lock.Lock() defer data1.lock.Unlock() data1.Pojo["1"] = "1" }(i) } fmt.Println(list) }
总结:对于需要操作同一份内容的,可以修改为指针类型,避免踩坑