(转载整理)CAS----无锁技术
CAS技术背景
关于同步,很多人都知道synchronized,Reentrantlock等加锁技术,这种方式也很好理解,是在线程访问的临界区资源上建立一个阻塞机制,需要线程等待;
其它线程释放了锁,它才能运行。这种方式很显然是奏效的,但是它却带来一个很大的问题:程序的运行效率。线程的上下文切换是非常耗费资源的,而等待又会有一定的时间消耗,
那么有没有一种方式既能控制程序的同步效果,又能避免这种锁带来的消耗呢?答案就是无锁技术。
cas的英文翻译全称是compare and set ,也就是【比较替换】技术;
悲观锁,乐观锁
- 悲观锁,顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。
- 乐观锁,顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制;
注意:cas技术是一种乐观锁
CAS原理
cas技术包含三个参数,CAS(V,E,N);
- V(variile)--------欲更新的变量;
- E (Excepted) ----预期的值;
- N (New) -----------新值;
若V等于E值的时候吗,将V的值设为N;
若V值和E值不同,则说明已经有其它线程对该值做了更新,则当前线程什么都不做,直接返回V值。
举个例子,假如现在有一个变量int a=5,我想要把它更新为6(那么变量是5,期望值可能是5也可能不是5,新值是6)
有两种情况:
期望值是5----》cas(5,5,6)----》修改成功;
期望值不是5----》cas(5,7,6)----》没有修改成功;
关于期望值E,我感觉这个E值是通过数据库查询得到的(没具体验证);
当多个线程同时使用CAS的时候只有一个最终会成功,而其他的都会失败;但是失败的线程并不会被挂起,仅仅是尝试失败,并且允许再次尝试(当然也可以主动放弃);
ABA问题和解决方案
- 问题描述:
火锅店在五一期间做活动,老用户凡是卡里余额小于20的,赠送10元,每人只可享受一次;最后发现赔钱赔哭了;
- 有问题的实现方式:
写一个判断,开启10个线程,然后判断小于20的,一律加20;
- 问题所在
有个线程A去判断账户里的钱此时是15,满足条件,直接+20,这时候卡里余额是35;但是此时不巧,正好在连锁店里,这个客人正在消费,又消费了20,此时卡里余额又为15,线程B去执行扫描账户的时候,发现它又小于20,又用过cas给它加了20,这样的话就相当于加了两次,这样循环往复肯定把老板的钱就坑没了!
- 解决办法
问题所在:数据库字段目前值是2,有两种情况,数据库字段没被改过一直是2,也可能是原本是2,改为7,又改回为2;
若对修改的次数有限制,用一个字段判断就不行了,得再加一个字段(时间戳);
类似于:cas(V+stamp,E+stamp,N);
//参数代表的含义分别是 期望值,写入的新值,期望标记,新标记值 public boolean compareAndSet(V expected,V newReference,int expectedStamp,int newStamp);
若【expectedStamp 跟 newStamp 一样】 并且 【期望值跟变量值一样】,则修改;否则不修改;
上一篇: jenkins
下一篇: maven的用法和几个常用的命令