cas原理
cas是compareAndSwap的缩写,可以看出就是比较比替换的意思。cas中有三个值,内存值V,旧的预期值E,更新值U,当且仅当V==E时,才进行更新,否则返回V。
cas应用
以java.util.concurrent包中的AtomicInteger为例。先演示代码:
public class AtomicIntegerTest {
private static AtomicInteger atomicInteger=new AtomicInteger(5);//设置初始值
public static void main(String[] args) {
atomicInteger.compareAndSet(0,1);//0!=5,不变
atomicInteger.compareAndSet(2,3);//2!=5,不变
atomicInteger.compareAndSet(3,4);//3!=5,不变
atomicInteger.compareAndSet(5,2);//5==5,更新为2
atomicInteger.compareAndSet(0,4);//0!=2,不变
System.out.println("result:"+atomicInteger.get());
}
}
输出结果是:result:2
源码:
/**使用 Unsafe.compareAndSwapInt()进行更新*/
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
/**静态代码块对valueOffset进行初始化*/
static {
try {
valueOffset = unsafe.objectFieldOffset
(java.util.concurrent.atomic.AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
/**使用volatile修饰value,保证value值的一致性*/
private volatile int value;
/**
* 有参构构造方法
*/
public AtomicInteger(int initialValue) {
value = initialValue;
}
/**
* 无参构造方法
*/
public AtomicInteger() {
}
/**
* 获取值
*/
public final int get() {
return value;
}
/**
* 设置值
*/
public final void set(int newValue) {
value = newValue;
}
/**
* 最终设置为给定值。
*/
public final void lazySet(int newValue) {
unsafe.putOrderedInt(this, valueOffset, newValue);
}
/**
* 原子地设置为给定值并返回旧值。
*
*/
public final int getAndSet(int newValue) {
return unsafe.getAndSetInt(this, valueOffset, newValue);
}
/**
*
* 若当前值等于期望的值,则更新给定的更新值
*
*/
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
/**
*自增1
*
*/
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
/**
* 自减1
*
*/
public final int decrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
}
/**
* 增加给定的值
*
*/
public final int addAndGet(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
}
/**
* 更新并返回原先的值
*/
public final int getAndUpdate(IntUnaryOperator updateFunction) {
int prev, next;
do {
prev = get();
next = updateFunction.applyAsInt(prev);
} while (!compareAndSet(prev, next));
return prev;
}
/**
* 返回更新之后的值
*/
public final int updateAndGet(IntUnaryOperator updateFunction) {
int prev, next;
do {
prev = get();
next = updateFunction.applyAsInt(prev);
} while (!compareAndSet(prev, next));
return next;
}
原子包还有以下,用法基本一样。
cas中的ABA问题
CAS可以有效的提升并发的效率,但同时也会引入ABA问题。
如线程1从内存X中取出A,这时候另一个线程2也从内存X中取出A,并且线程2进行了一些操作将内存X中的值变成了B,然后线程2又将内存X中的数据变成A,这时候线程1进行CAS操作发现内存X中仍然是A,然后线程1操作成功。虽然线程1的CAS操作成功,但是整个过程就是有问题的。比如链表的头在变化了两次后恢复了原值,但是不代表链表就没有变化。
所以JAVA中提供了AtomicStampedReference/AtomicMarkableReference来处理会发生ABA问题的场景,主要是在对象中额外再增加一个标记来标识对象是否有过变更。