[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子類
- 鎖小結
- 堵塞隊列
- 生產者消費者模型
- 線程池