什么时候需要用到锁?
当程序中就一个线程的时候,是不需要加锁的,但是通常实际的代码不会只是单线程,所以这个时候就需要用到锁了,那么关于锁的使用场景主要涉及到哪些呢?
- 多个线程在读相同的数据时
- 多个线程在写相同的数据时
- 同一个资源,有读又有写
互斥锁(sync.Mutex)
互斥锁是一种常用的控制共享资源访问的方法,它能够保证同时只有一个 goroutine 可以访问到共享资源(同一个时刻只有一个线程能够拿到锁)
先通过一个并发读写的例子演示一下,当多线程同时访问全局变量时,结果会怎样?
package main
import ("fmt")
var count int
func main() {
for i := 0; i < 2; i++ {
go func() {
for i := 1000000; i > 0; i-- {
count ++
}
fmt.Println(count)
}()
}
fmt.Scanf("\n") //等待子线程全部结束
}
运行结果:
980117
1011352 //最后的结果基本不可能是我们想看到的:200000
修改代码,在累加的地方添加互斥锁,就能保证我们每次得到的结果都是想要的值
package main import ("fmt" "sync" ) var ( count int lock sync.Mutex ) func main() { for i := 0; i < 2; i++ { go func() { for i := 1000000; i > 0; i-- { lock.Lock() count ++ lock.Unlock() } fmt.Println(count) }() } fmt.Scanf("\n") //等待子线程全部结束 } 运行结果: 1952533 2000000 //最后的线程打印输出