[TOC]
## 简介
CAS是Compare-and-swap(比较与替换)的简写,是一种有名的无锁算法。
CAS指令需要三个操作数,分别是
* 内存地址(在Java内存模型中可以简单理解为主内存中变量的内存地址)
* 旧值(在Java内存模型中,可以理解工作内存中缓存的主内存的变量的值)
* 新值
CAS操作执行时,当且仅当主内存对应的值等于旧值时,处理器用新值去更新旧值,否则它就不执行更新。但是无论是否更新了主内存中的值,都会返回旧值,上述的处理过程是一个原子操作。
所谓的CAS自旋,指的就是如果执行一次CAS失败。那说明在执行“获取-设置”操作的时候值已经有了修改,那么旧值替换成内存地址的值,然后再次循环进行下一次操作,直到设置成功为止。
## CAS在Java中的实现
Java程序中才可以使用CAS操作,该操作由sun.misc.Unsafe类里面的compareAndSwapInt和 compareAndSwapLong 等几个方法包装提供。
以AtomicInteger#incrementAndGet()为例子
~~~
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
private static final long VALUE;
static {
try {
//AtomicInteger对象value成员变量在内存中的偏移量。我们可以简单地把valueOffset理解为value变量的内存地址。
VALUE = U.objectFieldOffset
(AtomicLong.class.getDeclaredField("value"));
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
public final boolean compareAndSet(long expect, long update) {
/**
* 第一个参数object是当前对象
* 第二个参数offest表示该变量在内存中的偏移地址(CAS底层是根据内存偏移位置来获取的)
* 第三个参数expected为旧值
* 第四个参数x为新值。
*/
return U.compareAndSwapInt(this, VALUE, expect, update);
}
~~~
在java中,我们主要分析Unsafe类,因为所有的CAS操作都是它来实现的,在Unsafe类中这些方法也都是native方法
~~~
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6)
~~~
由于Unsafe类不是提供给用户程序调用的类(Unsafe.getUnsafe()的代码中限制了只有启动类加载器(Bootstrap ClassLoader)加载的Class才能访问它)。因此,如果不采用反射手段,我们只能通过其他的Java API来间接使用它,如J.U.C包里面的整数原子类,其中的compareAndSet()和getAndIncrement()等方法都使用了Unsafe类的CAS操作。
~~~
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) {
oop p = JNIHandles::resolve(obj);
if (p == NULL) {
volatile jint* addr = (volatile jint*)index_oop_from_field_offset_long(p, offset);
return RawAccess<>::atomic_cmpxchg(x, addr, e) == e;
} else {
assert_field_offset_sane(p, offset);
return HeapAccess<>::atomic_cmpxchg_at(x, p, (ptrdiff_t)offset, e) == e;
}
} UNSAFE_END
~~~
unsafe.cpp最终会调用atomic.cpp, 而atomic.cpp会根据不同的处理调用不同的处理器指令
## 参考资料
[Java并发编程:CAS操作](https://blog.csdn.net/fei20121106/article/details/83186222)
- Java
- Object
- 内部类
- 异常
- 注解
- 反射
- 静态代理与动态代理
- 泛型
- 继承
- JVM
- ClassLoader
- String
- 数据结构
- Java集合类
- ArrayList
- LinkedList
- HashSet
- TreeSet
- HashMap
- TreeMap
- HashTable
- 并发集合类
- Collections
- CopyOnWriteArrayList
- ConcurrentHashMap
- Android集合类
- SparseArray
- ArrayMap
- 算法
- 排序
- 常用算法
- LeetCode
- 二叉树遍历
- 剑指
- 数据结构、算法和数据操作
- 高质量的代码
- 解决问题的思路
- 优化时间和空间效率
- 面试中的各项能力
- 算法心得
- 并发
- Thread
- 锁
- java内存模型
- CAS
- 原子类Atomic
- volatile
- synchronized
- Object.wait-notify
- Lock
- Lock之AQS
- Lock子类
- 锁小结
- 堵塞队列
- 生产者消费者模型
- 线程池