在对象中引入Mutex来保证原子性,但是当对象是值引用的时候,发现索没有效果。它内部的实现逻辑到底是怎么样的?
代码如下:
package main
import (
"fmt"
"sync"
)
//这里声明了对象
type people struct {
sync.Mutex
}
//它的值类型的方法
func (p people) test(str string) {
p.Lock();
defer p.Unlock();
for i := 0; i < 5; {
fmt.Println(str, i)
i++
}
}
func main() {
var user people
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
user.test("go1")
}()
go func() {
defer wg.Done()
user.test("go2")
}()
wg.Wait()
}
这样执行的话,看不出效果来,然后加上这样一行代码:
func (p people) test(str string) {
p.Lock();
defer p.Unlock();
for i := 0; i < 5; {
fmt.Println(str, i)
//加的代码在这里!这里!
time.Sleep(time.Second)
i++
}
}
发现执行的结果如下:
go2 0
go1 0
go2 1
go1 1
go1 2
go2 2
go2 3
go1 3
go1 4
go2 4
疑惑点:在整个逻辑过程中,只有一个变量user,没有发生值拷贝的过程,怎么好端端的锁就不生效了呢
首先mutex不能被拷贝,一旦mutex被拷贝,加锁及解锁就作用在不同的mutex对象上,自然就失去了效果.
另外对于方法的接收对象,接收者是值和指针是有本质区别的:
1.当接收者是指针时进行函数调用时传递的是该对象的指针.
2.当接收者是值时进行函数调用传递的就是值拷贝.
这里可以通过在函数调用中对对象的值进行更改进行验证.
因此,people对象进行函数调用时,people已经拷贝了新值,生成了新的mutex,所以锁就失效了.这里将test方法接收者改成*people即可.