假设有多个线程想要操作同一个资源对象,我们首先想到的是使用互斥锁,但是互斥锁是悲观的。
悲观,即操作系统会悲观的认为如果不严格同步线程调用,那么一定会产生异常,所以互斥锁会将资源锁定,只供一个线程使用,而阻塞其他线程。
但如果大部分操作是读操作,就没必要在每次调用时锁定资源,或者是同步代码块的执行耗时远远小于线程切换的耗时,这就本末倒置。
因此,我们在一些情况下,不想让操作系统那么悲观,不想过度使用互斥锁。思考是否可以不对共享资源进行锁定,也能对线程的调用进行协调?--->引出CAS
CAS(compare and swap比较然后交换)
举例
假设资源对象为女神,手中的牌子正面为0,反面为1,0表示今天有空,并且表示谁先约到就和谁先共进晚餐,1表示没空。
现有线程A和线程B,且牌子为0;此时A线程先抢到时间片(女神)并将牌子改为1,线程B虽然也到了,但是已经发现牌子状态被改变,只好遵守规则。
当资源状态为0的一瞬间,AB线程都读到了,并且认为当前资源对象的状态值为0,此时它们会各自产生两个值old value(代表读到的资源对象的状态值)和new value(代表期望将资源对象状态值更新为想要的值),此时读到的状态值old value为0,new value为1(因为自己把值改为1,就表示已经约上了)
两个线程都去争抢,如果线程A抢到了时间片,将old value与资源对象的状态值进行compare比较发现一致,于是将牌子(状态值)swap为new value,线程B慢了一步,比较发现状态值已经被改为了1,和old value不一致,放弃swap操作 。
但是我们并不会让线程B直接放弃,而是使其自旋(即不断地重试CAS操作) ,并且会配置自旋次数防止死循环,如果在自旋的过程中发现牌子状态值变成了0,则会再次去争抢约会机会,如果线程B耐心耗尽(配置的自旋次数),则会放弃,不再打扰。
代码实现非常简单,但是可以发现并没有进行同步操作,说明线程还是不安全的,是否会出现线程AB同时获得资源,三个人约会?如果想解决同步问题,还是要加锁吗?
答案是,各种不同架构的CPU都提供了指令级别的CAS原子操作,CPU已经原生的支持了CAS。
通过CAS实现同步,不会锁定资源,而且当某一个线程需要修改共享的资源对象时,总是会乐观的认为其状态值没有被其他线程修改过(即不会出现同时抢占资源的情况),而是每次都是由自己去compare状态值。
虽然该机制称为乐观锁,但并不恰当,因为并没有用到锁,而是无锁的同步机制