源碼說話,咱們看一下getAndIncrement方法:java
1 //該方法功能是Interger類型加1 2 public final int getAndIncrement() { 3 //主要看這個getAndAddInt方法 4 return unsafe.getAndAddInt(this, valueOffset, 1); 5 } 6 7 //var1 是this指針 8 //var2 是地址偏移量 9 //var4 是自增的數值,是自增1仍是自增N 10 public final int getAndAddInt(Object var1, long var2, int var4) { 11 int var5; 12 do { 13 //獲取內存值,這是內存值已是舊的,假設咱們稱做指望值E 14 var5 = this.getIntVolatile(var1, var2); 15 //compareAndSwapInt方法是重點, 16 //var5是指望值,var5 + var4是要更新的值 17 //這個操做就是調用CAS的JNI,每一個線程將本身內存裏的內存值M 18 //與var5指望值E做比較,若是相同將內存值M更新爲var5 + var4,不然作自旋操做 19 } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); 20 21 return var5; 22 }
解釋一下getAndAddInt方法的流程:
假設有一下情景:多線程
簡單來講,就是將工做內存的值與主內存的值來進行比較,若是相等,說明沒有被其餘線程修改,則進行賦新值操做,若是不相等,說明主內存的數據被其餘線程更改過,則此時須要更新工做內存的副本值,而且從新獲取主內存的值,再次進行比較,直到兩者相等爲止;jvm
非阻塞的輕量級的樂觀鎖,經過CPU指令實現,在資源競爭不激烈的狀況下性能高,相比synchronized重量鎖,synchronized會進行比較複雜的加鎖、解鎖和喚醒操做。性能
- ABA問題: 線程C、D;線程D將A修改成B後又修改成A,此時C線程覺得A沒有改變過,java的原子類AtomicStampedReference,經過控制變量值的版本號來保證CAS的正確性。具體解決思路就是在變量前追加上版本號,每次變量更新的時候把版本號加一,那麼A - B - A就會變成1A - 2B - 3A。
- 自旋時間過長,消耗CPU資源,若是資源競爭激烈,多線程自旋長時間消耗資源