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)
}

总结:对于需要操作同一份内容的,可以修改为指针类型,避免踩坑

posted @ 2023-08-20 13:41  美好生活我心往之  阅读(19)  评论(0编辑  收藏  举报