CAS
翻译成中文为比较并交换,是对cpu的层面而言,在java中主要是通过java.util.concurrent.atomic包下的一些原子操作类实现的
这些类的实现是通过unsafe类实现,而unsafe类执行的是native方法,底层是由c++写的
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
public class MyTest {
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(1);
//1改为2
System.out.println(atomicInteger.compareAndSet(1, 2));
System.out.println(atomicInteger.get());
//2改为3
System.out.println(atomicInteger.compareAndSet(2, 3));
System.out.println(atomicInteger.get());
//2改为4
System.out.println(atomicInteger.compareAndSet(2, 4));
System.out.println(atomicInteger.get());
}
}
//执行结果
true
2
true
3
false
3
但是普通的cas是有ABA的问题的,也就是如果A和B同时拿到变量的值为1,B线程将i变量改成了2,在改成了1.这是A线程修改值的时候,发现拿到的值为1,与内存中的值相等,所以他也将值修改了,但是原则上这个是不准修改的
AtomicReference和AtomicStampedReference都是对于对象的引用,与AtomicInteger是非常相似的,只不过AtomicInteger是对整数的封装,AtomicStampedReference较于AtomicReference,内部添加了时间戳的验证,在compareAndSet时,不仅要比较期望值,还要比较一个时间戳,其实就相当于版本号,每一次compareAndSet就修改对应的时间戳(往上加),相当于compareAndSet时做了双重检测,就完美的解决了ABA问题
public class MyTest {
public static void main(String[] args) {
AtomicStampedReference<String> stringAtomicStampedReference = new AtomicStampedReference<String>("A",1);
//将A改为B
System.out.println(stringAtomicStampedReference.compareAndSet("A", "B", 1, 2));
System.out.println(stringAtomicStampedReference.getReference());
System.out.println(stringAtomicStampedReference.getStamp());
//将B改为A
System.out.println(stringAtomicStampedReference.compareAndSet("B", "A", 2, 3));
System.out.println(stringAtomicStampedReference.getReference());
System.out.println(stringAtomicStampedReference.getStamp());
//将A改为B
System.out.println(stringAtomicStampedReference.compareAndSet("A", "B", 1, 2));
System.out.println(stringAtomicStampedReference.getReference());
System.out.println(stringAtomicStampedReference.getStamp());
}
}
//执行结果
true
B
2
true
A
3
false
A
3