欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

CAS操作

程序员文章站 2022-03-08 17:52:45
...

CAS操作 - Compare and Swap

概述

  • Compare and Swap,比较并操作,CPU指令,在大多数处理器架构,包括IA32、Space中采用的都是CAS指令,CAS的语义是“我认为V的值应该为A,如果是,那么将V的值更新为B,否则不修改并告诉V的值实际为多少”,CAS是项乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。

  • CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
    CAS操作

例子

  • 模拟CAS实现的计数器:
public class CASCount implements Runnable {

private SimilatedCAS counter = new SimilatedCAS();

@Override
public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println(this.increment());
}
}

public int increment() {
int oldValue = counter.getValue();
int newValue = oldValue + 1;
while (!counter.compareAndSwap(oldValue, newValue)) { //如果CAS失败,就去拿新值继续执行CAS
oldValue = counter.getValue();
newValue = oldValue + 1;
}
return newValue;
}

public static void main(String[] args) {
Runnable run = new CASCount();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}

}

class SimilatedCAS {

private int value;
public int getValue() {
return value;
}

// 这里只能用synchronized了,毕竟无法调用操作系统的CAS

public synchronized boolean compareAndSwap(int expectedValue, int newValue) {

if (value == expectedValue) {
value = newValue;
return true;
}
return false;
}
}

输出结果:
CAS操作

  • 计时器原理
    CAS操作

    CAS实现原子性操作的三大问题

  • ABA问题

因为CAS需要在操作值的时候,检查值有没有发生变化,如果发生变化则更新,但是如果一个值为A,变成了B,又变成了A,那么使用CAS进行检查时就会发现它的值没有发生变化,但实际上发生变化了。ABA问题的解决思路就是使用版本号,在变量前边追加版本号,每次变量更新的时候把版本号加1,那么A→B→A就会变成1A→2B→3A。从java1.5开始,JDK提供了AtomicStampedReference、AtomicMarkableReference来解决ABA的问题,通过compareAndSet方法检查值是否发生变化以外检查版本号知否发生变化。(AtomicStampedReference能够得到变化的次数这里下边会介绍到)

  • 循环时间长开销大

自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销。

  • 只能保证一个共享变量的原子操作

当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁。还有一个取巧的办法,就是把多个共享变量合并成一个共享变量来操作。比如,有两个共享变量i=2,j=a,合并一下ij=2a,然后用CAS来操作ij。从Java 1.5开始,JDK提供了AtomicReference类来保证引用对象之间的原子性,就可以把多个变量放在一个对象里来进行CAS操作。

相关标签: CAS