什么是CAS
CAS,全称Compare and swap,字⾯意思为⽐较并交换,⼀个CAS涉及到以下操作:
内存中有数值A,寄存器1中有A,寄存器2中有B
1,比较内存中数值是否和寄存器中数值相等
2,如果相等,将另一个寄存器的值写入内存
3,返回交换是否成功
如:比较内存和寄存器1中的值,均为A,故将内存中的A和寄存器2中的B交换,返回true.
伪代码示例
boolean CAS(address, expectValue, swapValue){
if(address == expectValue){
address = swapValue;
return true;
}
return false;
}
CAS是怎么实现的
针对不同的操作系统,JVM⽤到了不同的CAS实现原理,简单来讲:
java的CAS利⽤的的是unsafe这个类提供的CAS操作
unsafe的CAS依赖了的是jvm针对不同的操作系统实现的Atomic::cmpxchg
Atomic::cmpxchg的实现使⽤了汇编的CAS操作,并使⽤cpu硬件提供的lock机制保证其原⼦
简⽽⾔之,是因为硬件予以了⽀持,软件层⾯才能做到
CAS的应用
1.原子类
在java.util.concurrent.atomic包的类,都是基于CAS方法来实现的,如AtomicInteger类,它的getAndIncrement方法就相当于原子的i++操作,这样不使用锁也可以实现多线程的自增案例.

public static void main(String[] args) throws InterruptedException {
AtomicInteger atomicInteger = new AtomicInteger();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
atomicInteger.getAndIncrement();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
atomicInteger.getAndIncrement();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(atomicInteger.get());
}
2.实现自旋锁
伪代码实现
public class Lock {
private Thread owner = null;
public void lock() {
//加锁时,如果锁的持有者为空,那么将持有者替换为加锁线程 然后退出
//如果不为空,那么CAS返回false,while判断为true持续尝试加锁
while(!CAS(this.owner, null, Thread.currentThread())){
}
}
public void unlock() {
this.owner = null;
}
}
CAS的ABA问题
ABA问题指,一个线程想要通过CAS修改A为其他值,预期为值不变就修改,但是在读取后其他线程将A替换为了B,然后又替换为了A,但是此时值从A变为B又变为A,此时的值被修改过,但是CAS依旧会判断值仍为A不变,修改值.
bug举例:某人去ATM取钱,卡中余额有1000,要取出500元,点击取款时ATM卡住了,他就点了两次,就会出现两个线程进行CAS修改.线程1读取余额1000后被调走了,线程2正常执行完毕这个CAS操作,扣款500元.当线程2执行完毕后,又有人给他打了500元,此时余额为1000元线程1再开始执行会判断余额为1000再次扣款500元.这样就会出现问题.
这是CAS进行双向修改(增加和减少)引发的问题.
解决方案:引入版本号,在读取数值时,不仅读取数值,也要读取数值的版本号,在修改数值时,也要修改数值的版本号,这样就算两次数值相同,版本号也不同,根据版本号不同,判断出不应该进行操作.
84万+

被折叠的 条评论
为什么被折叠?



