文章目录
- CAS
- 什么是CAS
- 如何理解CAS
- CAS伪代码
- CAS怎么实现的
- CAS的应用
- 实现自旋锁
- CAS的ABA问题
- 什么是ABA问题
- ABA问题的解决
CAS
什么是CAS
CAS:全称是Compare and swap也就是比较并交换什么是比较并交换呢?我们来举个例子
假如说原内存中的数据是V,旧的预期值是A需要修改的值是B
首先比较A与V是否相等如果相等的话那就更改将B写入V
返回操作是否成功
如何理解CAS
CAS伪代码
boolean CAS(address, expectValue, swapValue) {
if (&address == expectedValue) {&address = swapValue;return true;}return false;
}
上面就是一个CAS的伪代码。当然了上述代码中的操作不是原子的这只是一个伪代码。
CAS怎么实现的
CAS的应用
CAS可以用来实现原子类。比如说java中提供了Atomiclnteger类其中的getAndcrement相当于++操作。那么他内部的伪代码是怎么样的呢?
class testAtom{private int value;boolean CAS(int value,int oldvalue,int swapvalue){if(value==oldvalue){this.value=swapvalue;return true;}return false;}public testAtom(int value){this.value=value;}public int getAndcrement(){int oldvalue=value;while(CAS(value,oldvalue,oldvalue+1)==false){oldvalue=value;}return value;}public int getValue() {return value;}
}
他的一个逻辑思路是怎么样的呢?如下图
首先我们假设t1线程先开始当t1刚开始的oldvalue等于value的时候那么CAS中就可以进入if判断,if判断后进入修改了this.value的值然后返回了true从而导致value和oldvalue不再相等。于是当t2线程再次调用getAndcrement()的时候就会再次进入CAS中然后此时的value已经和oldvalue不相等了当不相等的时候就会再次执行while循环当循环再次执行的时候,CAS由于oldvalue被改成和value一样的值从而导致我们的if判断可以进入从而再次实现了++操作。
实现自旋锁
CAS实现更灵活的锁。获取更多的控制权
class SpinLock{private Thread oner=null;public void lock(){while(!CAS(this.oner,null,Thread.currentThread())){}}public void unlock(){this.oner=null;}
}
CAS的ABA问题
什么是ABA问题
ABA问题:假设存在两个线程有一个共享的变量叫做num初始值为1
接下来线程t1想使用CAS把这个变量修改成2;那么需要进行下面的这个操作
先读取num的值计入到oldnum中
使用CAS判定当前的num值是否为1如果是1那就使其变为2.
但是在t1线程执行这个操作的时候t2线程也有可能在做出行动。此时t2线程可能会将num修改成了2然后又修改成了1如下图
那么这时候可能就有疑问说那这个有什么关系呢?我们可以想象一下下面的情景。
假如说你有100块钱,然后你要去银行取走50。这时候当你取走五十的时候你的妈妈又给你的银行卡打了五十。那么这时候是不是就造成了ABA问题呢?我们来看一下。
首先num=100
然后创建了t1和t2:线程要从100中扣除50。这时候t1和t2都希望能将num从100改为五十。
这时候t1线程先进性比较发现此时的num和oldnum值相等因此执行了num=swapnum此时num由100变为了50
然后此时t2线程应该执行失败才对可是这时候你的老妈给你打了五十并且创建了线程将你的 num由50变为了100
这时候t2线程再去执行的时候就发现num=100然后就会再次修改将100改为五十。
ABA问题的解决
讲完了上面我们要知道ABA问题如何解决呢我们可以引入一个版本号让这个版本号初始值为0当num执行一次改变的时候我们让版本号++然后每次判断是否需要改变都是比较版本号来进行,这时候就可以做到避免上述的问题了。怎么实现请看上面。