概念-乐观锁、悲观锁

听到 乐观锁、悲观锁的概念,搜了下,摘要出为能理解的尽量短的文字说明:

概念

悲观锁:正常的经典使用方式是叫悲观锁,先取锁,成功取得后才做操作(不论是读还是写)。

乐观锁:乐观并发控制相信事务之间的数据竞争(data race)的概率是比较小的,因此尽可能直接做下去,直到提交的时候才去锁定,所以不会产生任何锁和死锁。

其他说明

乐观锁,提交的时候,如果冲突,则返回给用户异常信息,让用户决定如何去做。

悲观锁主要分为共享锁 和排他锁

  • 共享锁【shared locks】又称为读锁,简称 S 锁。顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改。
  • 排他锁【exclusive locks】又称为写锁,简称 X 锁。顾名思义,排他锁就是不能与其他锁并存,如果一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁,包括共享锁和排他锁。获取排他锁的事务可以对数据行读取和修改。

这么看自己实际使用的时候,普通的锁,内部应该就是个排他锁;而读写锁似乎内部一个排他锁和一个共享锁组成,读的加锁和解锁过程应该是用了内部共享锁,写的加锁和解锁则应该是用了内部的排他锁。

怀疑似乎这概念应该是 从java的 CAS  包的实现传播开的

扩展

简单搜了下 CAS的概念,即compare and swap(比较与交换),是一种有名的无锁算法。瞄了眼,似乎是有一套理论来说明它的实现和优缺点。

了解cas时,自然的也会涉及到个 自旋锁的概念。下面说的是我的理解,没找到这个概念的最初出处,并不确信也未做验证。

自旋锁似乎是说的取锁的方式,普通的加锁(或者说尝试取锁)时,如果没获取成功,加锁函数可能会让自己卡在调用函数处;而自旋锁的方式是尝试获取,如果不成功立刻进行下一次获取尝试,一直死循环到获取成功。

这里说的卡住,应该是让渡出当前的线程调度,系统会挂起(或其他操作)当前线程,改去执行其他线程。

而自旋锁的死循环获取方式则是不会主动让渡。

当然系统的调度cpu分配规则,或许也会因为时间片到了而阻塞自旋锁的线程,但这对于普通加锁方式的线程应该也是一样没差别的。

每次cpu重新调度到当前线程的时候,执行代码依次还是沿用各自的方式,

如果普通取锁方式,出现了等待,是否是注册了下,等到资源释放了才会通知改变该线程的状态,不通知期间系统不再会调度该线程(给它分配时间片)?

非自旋的获取会有内核模式切换的代价。为什么有这个代价,是那个获取锁的函数本身就是个系统调用造成的,还是获取失败的情况下会产生中断,让出执行权限造成的?目前不太确定。

如果说自旋锁没有内核模式切换的代价。那也就是说,它那尝试的操作(那个函数调用)判断,肯定不是个系统调用。

普通锁和自旋锁分别对应概念:mutex和spin lock 及 sleep-waiting和busy-waiting的区别

参考

主要参考摘录自:

https://www.jianshu.com/p/d2ac26ca6525

https://www.cnblogs.com/wangshaowei/p/14358774.html

原文地址:https://www.cnblogs.com/xiarl/p/14852759.html