在高并发下或多goroutine同时执行下,可能会同时读写同一块内存

 

Golang乐观锁和悲观锁

修改一个数值的步骤:

  ①把想修改的数值从某个地方取出来

  ②在取出来的数值修改为期望值

  ③把修改后的数值保存到原来的地方

 

可能存在的问题:

  如果两个goroutine同时执行修改数值的步骤,都要进行第③步了,这么看下来,先执行第③步的goroutine做了白功,因为后面那个goroutine紧接着就把这个值覆盖了

 

悲观锁认为:

  每次修改变量的值的时候总会遇到并发,一定会存在其他goroutine也在修改这个变量的值。为了防止此类情况发生,一定要严格执行 ①先上锁 ②执行修改的3个步骤 ③解锁,以保证数据的精确。

  悲观锁有互斥锁和读写锁

乐观锁认为:

  每次修改变量值的时候不会遇到并发这么倒霉的事,所以3个步骤中直接不上锁走完①②步,到了要执行第③步的时候,检查一下这个数值是否改变,如果没有,则执行第③步;如果被已经被别的goroutine修改了,那么重新执行①②③。整个环节不存在加锁和解锁的操作

 

 

悲观锁】互斥锁 & 读写锁

互斥锁:任何一个goroutine读或者写,其他goroutine都只能等待。适用于读写相当的场景

读写锁:只要没有goroutine写,可以有多个goroutine一起读。一旦有一个goroutine要开始写,其他goroutine都不能读和写。适用于读多写少的场景

看起来读写锁效率要高一些,但一般情况下却是互斥锁更加高效?读写锁的底层实现是互斥锁+计数器,只有在锁住的时候业务耗时过长,读写冲突更严重的时候,读写锁才有优势

 

【atomic原子操作】

原子操作是指不会被线程调度机制打断的操作;原子操作一旦开始,就一直运行到结束,中间不会有任何 context switch(上下文切换,从当前线程切换到另一个线程)。(from 百度百科)

对于编程语言中变量的修改,可以认为原子操作需满足下面的条件:① 变量的读写过程不可中断(不可以读到一半做其他事情,也不可写到一半做其他事情),② 变量的读写过程不可同时进行(不可以写变量的同时读取变量,防止读取到仅更新了一半的变量值;也不可以写变量的同时另一个线程也在写这个变量,防止其中一个更新无效)。

可惜只能对数值进行操作