CAS是什麼java
(1) CAS(Compare and Swap) 比較並交換, 比較並交換是在多線程併發時用到的一種技術安全
(2) CAS是原子操做, 保證併發安全性, 而不是保證併發同步.多線程
(3) CAS是一個CPU指令併發
(4) CAS是一種非阻塞的輕量級樂觀鎖jvm
什麼是樂觀鎖和悲觀鎖性能
樂觀鎖, 嚴格來說並非鎖, 他是經過原子性來保證數據的同步, 樂觀的認爲在數據操做期間沒有其餘線程影響. 而悲觀鎖例如: synchronize 認爲在數據操做期間必定會有其餘線程影響, 因此會經過併發同步的方式來保證數據的正確. 因此CAS不會保證線程同步, 樂觀地認爲在數據更新期間沒有其餘線程影響.this
CAS原理atom
CAS, 比較並交換, 是將內存值更新爲須要的值, 可是有個條件, 就是內存值必須與指望值相同. 例如: 指望值 E, 工做內存值 M , 更新值 U, 只有 當 E == M 時, 將M 更新爲U. spa
CAS應用操作系統
因爲CAS是CPU指令,咱們只能經過JNI與操做系統交互,關於CAS的方法都在sun.misc包下Unsafe的類裏 java.util.concurrent.atomic包下的原子類等經過CAS來實現原子操做。
CAS指令
原子類例如AtomicInteger, 其中的getAndIncrement方法就用了CAS.
public final int getAndIncrement() { //主要看這個getAndAddInt方法 return unsafe.getAndAddInt(this, valueOffset, 1); } //var1 是this指針 //var2 是地址偏移量 //var4 是自增的數值,是自增1仍是自增N public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { //獲取主內存值,這是內存值已是舊的,假設咱們稱做指望值E var5 = this.getIntVolatile(var1, var2); //var5是指望值E,var5 + var4是要更新的值 //這個操做就是調用CAS的JNI,每一個線程將本身內存裏的內存值M和指望值E做比較, //若是相同將內存值M更新爲var5 + var4,並同步到主內存, 不然作自旋操 } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; }
流程:
1. 假設有兩個線程: A, B
2. jvm 中主內存爲1 , A, B 線程的工做內存爲1 (工做內存會拷貝一份主內存的值)
3. 當前指望值E爲1 , A, B 兩個線程作+1操做
4. 執行到getAndAddInt方法, var5 = 1 , var4 = 1,
(1) A線程將var5 與工做內存值M比較, 比較var5 是否等於1
(2) 若是相等, 則將工做內存值更新爲 var5+var4 , 並更新到主內存, 此時this指針的value = 2
(3) 若是不相等, 說明B線程先A線程進行了更新操做, 這時主內存值 = 2, A線程未更新成功繼續循環, var5 更新爲新主內存值 = 2, 由於this指針的value用volatile 修飾, 因此更新爲2, 這時繼續將 var5 與工做內存值M比較, 比較var5 是否等於 2 , 相等則將工做內存值更新爲var5 + var4, 並更新到主內存, 此時this指針的value = 3; 主內存值爲3;
(4) 若是一直不相等, 重複第三步直到相等退出更新.
CAS 優缺點
非阻塞的輕量級樂觀鎖, 經過CPU指令實現, 在資源競爭不激烈的狀況下性能高, 相比synchronize重量級悲觀鎖, synchronize有複雜的加鎖, 解鎖和喚醒線程操做.
(1) ABA 問題, 線程1, 2. 線程1 將A修改成B後又修改成A, 此時線程2覺得A沒有改變過. 而 J巴德原子類AtomicStampedReference, 經過控制變量值的版原本保證CAS的正確性.
(2) 自旋時間過長, 消耗CPU資源, 若是資源競爭激烈, 嘖多線程自旋時間長消耗資源.