原子操作CAS

原子操作CAS

1、CAS的基本原理

利用了现代处理器都支持的CAS的指令,循环这个指令,直到成功为止

CAS(Compare And Swap),指令级别保证了这是一个原子操作(指操作不会被线程调度机制打断)

它有3个操作数:内存值V,预期值A,更新值B,如果内存值V和期望值A相等,就把V修改为B,循环CAS操作,直到成功为止。


cas自旋.png

以AtomicInteger为例:

//++i
public final int incrementAndGet() {
  return U.getAndAddInt(this, VALUE, 1) + 1;
}
//i++
public final int getAndIncrement() {
  return U.getAndAddInt(this, VALUE, 1);
}
//额外提供了compareAndSet方法,第一个期望值,第二个希望修改成的值
public final boolean compareAndSet(int expect, int update) {
  return U.compareAndSwapInt(this, VALUE, expect, update);
}
//Unsafe类
public final int getAndAddInt(Object var1, long var2, int var4) {
  int var5;
  do {
    var5 = this.getIntVolatile(var1, var2);
    ////compareAndSwapInt是一个native方法,CPU原语指令,是连续执行不会被打断的,所以可以保证原子性。
  } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
  return var5;
}

AtomicInteger由硬件提供原子操作指令实现的。在非激烈竞争的情况下,开销更小,速度更快。

public static void main(String[] args) {
  AtomicInteger atomicInteger = new AtomicInteger(6);
  //true
  System.out.println(atomicInteger.compareAndSet(6,66));
  //false
  System.out.println(atomicInteger.compareAndSet(6,66));
}

AtomicInteger的compareAndSet方法就是CAS操作:

初始值6,调用 compareAndSet(6,66),期望值为6(相等),主内存中的值被修改为66,输出true;

第2次调用 compareAndSet(6,66),期望值为6,但此时主内存中的值为66,输出false。

2、CAS的问题
  • ABA问题

    变量A,修改为变量B,然后又修改为A,实际上已经修改过了。

    对于这个问题,每次修改加上类似版本戳的方式,JDK提供了:

    AtomicMarkableReference:是否修改过

    AtomicStampedReference:改过几次

  • 开销问题

    自旋CAS不成功,就会一直循环执行,直到成功,如果长时间不成功,会给CPU带来大的执行开销。

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

    这个问题可以采用合并共享变量的方式处理,JDK提供了AtomicReference类来保证引用对象之间的原子性,就可以把多个变量放在一个对象里来进行CAS操作

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容