[Go 并发编程实战课]01.Mutex 学习笔记
学习目标
了解互斥锁的实现机制
Go 标准库的互斥锁 Mutex 基本使用方法
Mutex 具体实现原理、易错场景和拓展用法
互斥锁的实现机制
互斥锁是并发控制的一个基本手段,是为了避免竞争而建立的一种并发控制机制。
临界区
在并发编程中,如果程序中的一部分会被并发访问或修改,那么,为了避免并发访问导致的意想不到的结果,这部分程序需要被保护起来,这部分被保护起来的程序,就叫做临界区。
使用互斥锁,限定临界区只能同时由一个线程持有。
Mutex 的基本使用方法
Mutex 实现了 Locker 接口
Locker 接口定义了锁同步原语的方法集
互斥锁 Mutex 就提供两个方法 Lock 和 Unlock:进入临界区之前调用 Lock 方法,退出临界区的时候调用 Unlock 方法:
当一个 goroutine 通过调用 Lock 方法获得了这个锁的拥有权后,其他请求锁的 goroutine 就会阻塞在 Lock 方法的调用上,直到锁被释放并且自己获取到了这个锁的拥有权。
不加锁的 Demo
每次运行都得到不同的结果,基本上不会得到理想中的结果 一百万。
因为 count++ 不是一个原子操作,它只是包含了读取变量 count 的当前值,对这个值加 1,把结果再保存到 count 中。因为不是原子操作,就有可能有并发问题。
使用 go run -race main.go
可以检测一下是不是有并发问题。
使用互斥锁 Demo
再运行,data race 没有警告,运行结果也是 1000000。
互斥锁的最佳实践 Demo
Mutex 嵌入到其他 struct 中使用
互斥锁封装成方法 Demo
可以把 获取锁、释放锁、计数加一的逻辑封装成一个方法,对外不需要暴露锁等逻辑。
如果嵌入的 strcut 有多个字段,一般把 Mutex 放在要控制的字段上面,然后使用空格把字段分隔开来。
思考
如果 Mutex 已经被一个 goroutine 获取了锁,其它等待中的 goroutine 们只能一直等待。那么,等这个锁释放后,等待中的 goroutine 中哪一个会优先获取 Mutex 呢?
评论