[备份] Java并发之CAS原理入门

介绍

通常情况下,共享变量在并发中的处理是使用synchronized关键字或lock

但是这种方式效率过低,是否存在一种更高效的处理方式:在修改共享变量之前,判断期望值和当前值,如果不一致则一直等待,如果相等那么修改共享变量。新的方式只需要在判断逻辑中加锁

 

CAS

原理

CAS全称是CompareAndSwap,比较并替换

CAS需要有3个操作数:内存地址V,旧的预期值A,即将要更新的目标值B CAS指令执行时,当且仅当内存地址V的值与预期值A相等时,将内存地址V的值修改为B,否则就什么都不做。整个比较并替换的操作是一个原子操作

CAS是通过JNI借助C语言实现的,例如指令cmpxchg

系统底层进行CAS操作时,会判断当前系统是否是多核心系统,会给总线加锁,然后执行CAS操作

CAS的问题:高并发情况下存在性能问题

 

ABA

如果存在以下的情况: 并发1:获取出数据的初始值是A,后续计划实施CAS,期望数据还是A,新值为B 并发2:将数据修改成B再修改回A 并发1:CAS检测发现被修改后的数据是A,修改为B

或者可以理解为丢失了一个版本更新

简单地模拟

打印如下,主线程并没有感受到这个值的变化

问题解决:

  1. 业务对数据敏感时,避免使用CAS
  2. 记录修改版本号判断,JDK中已有实现(AtomicStampedReference)

对上述案例的解决

成功解决

 

源码

JDK在sun.misc.unsafe类中实现

  1. public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
  2. public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
  3. public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);

var1:表示要操作的对象(比较并替换的对象) var2:表示要操作对象中属性地址的偏移量 var4:修改数据的期望值 var5:需要修为的新值