golang的同步包sync解析——互斥锁/读写锁
目录
1、临界资源访问存在的问题
如上图所示,会出现多个窗口卖出同一张票以及卖出负票的问题
2、使用WaitGroup等待一组线程的结束
由于一旦主协程执行结束,即时其他协程还没有执行完成也会退出,上面例子我们强制在主协程中设置休眠时间,但是这样做不太好,而使用WaitGroup可以解决上述问题
WaitGroup用于等待一组线程的结束。父线程调用Add方法来设定应等待的线程的数量。每个被等待的线程在结束时应调用Done方法。同时,主线程里可以调用Wait方法阻塞至所有线程结束。
如上图所示,这样做的话即时主线程执行完了也不会退出,直到等待的线程数量变为0了才会退出
3、互斥锁——处理临界资源中的并发问题
保证在任何时候都只能有一个goroutine来访问资源,其他goroutine都等待
相对于第一部分的代码,改进了如下两个地方:
- 加入了sync.Mutex互斥锁,解决了临界资源并发访问的问题
- 加入了sync.WaitGroup,解决了主协程一结束其他子协程就被强制结束的问题
4、读写锁——多读一写
RWMutex是读写互斥锁。该锁可以被同时多个读取者持有或唯一个写入者持有。RWMutex可以创建为其他结构体的字段;零值为解锁状态。RWMutex类型的锁也和线程无关,可以由不同的线程加读取锁/写入和解读取锁/写入锁。
读写锁有如下四个方法:
- 写操作的锁定和解锁分别是
func (*RWMutex) Lock
和func (*RWMutex) Unlock
;
- 读操作的锁定和解锁分别是
func (*RWMutex) Rlock
和func (*RWMutex) RUnlock
。
读写锁的区别在于:
- 当有一个 goroutine 获得写锁定,其它无论是读锁定还是写锁定都将阻塞直到写解锁;
- 当有一个 goroutine 获得读锁定,其它读锁定仍然可以继续;
- 当有一个或任意多个读锁定,写锁定将等待所有读锁定解锁之后才能够进行写锁定。
所以说这里的读锁定(RLock)目的其实是告诉写锁定,有很多协程或者进程正在读取数据,写操作需要等它们读(读解锁)完才能进行写(写锁定)。
我们可以将其总结为如下三条:
- 同时只能有一个 goroutine 能够获得写锁定;
- 同时可以有任意多个 gorouinte 获得读锁定;
- 同时只能存在写锁定或读锁定(读和写互斥)。