Java CAS(Compare And Swap)的一點理解
阿新 • • 發佈:2018-12-25
CAS: Compare And Swap, 即比較和替換。
思想: CAS的比較、替換操作是非阻塞操作, 它有3個引數分別為記憶體值、預期值和更新值。 當記憶體值和預期值匹配時則更新, 不匹配時直接返回。
PS: CAS比synchronized效率要好, 因為CAS是c語言實現的cpu鎖機制, synchronized是Java鎖。
簡單的說CAS提供了一種實現原子操作的方法, 都封裝在sun.misc.Unsafe類裡。 而在實際開發過程中, 並不建議直接操作Unsafe類, 而且使用基於Unsafe類實現的各個派生類。
這些類都提供了原子操作, 假設使用AtomicInteger模擬生產者消費者模式。
4個生產者執行緒、4個開發者執行緒。 生產者執行緒的作用是0到1, 消費者執行緒的作用是1到0。 程式碼裡並沒有同步控制邏輯(即沒有synchronized/Lock), 執行程式看看效果。AtomicInteger object = new AtomicInteger(0); for (int i = 0; i < 4; i++) { //邏輯上的生產者, 值從0到1 new Thread() { @Override public void run() { while (true) { try { Thread.sleep(100); } catch (Exception ex) { } System.out.println("判斷0執行緒,當前值是"+ object.get() + ", 返回值"+ object.compareAndSet(0, 1)); //compare函式是非阻塞 } } }.start(); //邏輯上的消費者, 值從1到0 new Thread() { @Override public void run() { while (true) { try { Thread.sleep(100); } catch (Exception ex) { } System.out.println("判斷1執行緒,當前值是" + object.get() + ", 返回值" + object.compareAndSet(1, 0)); //非阻塞 } } }.start(); }
程式執行正常, 並沒有報共享衝突錯誤。判斷0執行緒,當前值是0, 返回值true 判斷0執行緒,當前值是0, 返回值true 判斷1執行緒,當前值是0, 返回值false 判斷1執行緒,當前值是1, 返回值true 判斷0執行緒,當前值是0, 返回值true 判斷1執行緒,當前值是1, 返回值true 判斷1執行緒,當前值是1, 返回值true 判斷0執行緒,當前值是1, 返回值false 判斷0執行緒,當前值是0, 返回值true 判斷0執行緒,當前值是1, 返回值false 判斷1執行緒,當前值是1, 返回值true 判斷1執行緒,當前值是0, 返回值false 判斷0執行緒,當前值是0, 返回值true 判斷1執行緒,當前值是1, 返回值true
原理:
1、 volatile關鍵字保證這8個執行緒操作的是同一塊記憶體;
2、 原子性操作compareAndSet即比較並更新, 是在native層實現的, 原理見下面的2篇部落格。
CAS裡所有ABA問題其實就是值在改回來前不知道發生了什麼, 例如: 你讀取的值是1, 但前面可能經歷了3、2等值的情況。
使用AtomicStampedReference可以解決ABA問題, 因為每次更新值時都有一個時間戳。 在compareAndSet時既要比較值,也要比較時間戳是否一致。
public boolean compareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) {
Pair<V> current = pair;
return
expectedReference == current.reference &&
expectedStamp == current.stamp &&
((newReference == current.reference &&
newStamp == current.stamp) ||
casPair(current, Pair.of(newReference, newStamp)));
}
參考部落格:
https://www.jianshu.com/p/24ffe531e9ee
http://zl198751.iteye.com/blog/1848575