CAS操作原理与实现
文章目錄
- 前言
- 一、樂觀鎖和悲觀鎖
- 1.1樂觀鎖
- 1.2悲觀鎖
- 1.3自旋鎖
- 二、CAS
- 2.1什么是CAS?
- 2.2ABA 問題
- 總結
前言
Java中的鎖主要用于保障線程在多并發情況下數據的一致性。鎖從樂觀和悲觀的角度可分為樂觀鎖和悲觀鎖,JVM還巧妙的設計了自旋鎖更快的使用CPU資源。
一、樂觀鎖和悲觀鎖
1.1樂觀鎖
樂觀鎖采用樂觀的思想處理數據,即每次讀取數據時都認為別人不會修改該數據,不會進行加鎖。
JAVA中的樂觀鎖大部分是通過CAS操作實現的,CAS是一種原子更新操作,對數據操作之前會比較要更新的值和預期的值是否相同,如果相同才會進行更新,否則會再次嘗試,直到成功。
1.2悲觀鎖
悲觀鎖采用悲觀的思想處理數據,認為每次讀取數據時別人都會修改數據,所以每次讀寫數據都會加鎖,不允許別的線程同時操作。
JAVA中的悲觀鎖大部分基于AQS(抽象的隊列同步器)實現。AQS定義了一套多線程訪問共享資源的同步框架,許多同步類的實現都依賴它,例如:ReentranLock等。
1.3自旋鎖
自旋鎖( SpinLock),spin在英文中用于描述紡紗的紗輪瘋狂自轉的樣子。認為如果持有鎖的線程在很短的時間就會釋放鎖資源,那么等待的線程只需要等一等,重試不斷的去嘗試獲取鎖(自旋),不需要進入阻塞、掛起狀態。
自旋鎖的優點
1.非常適合占用鎖時間非常短的場景,極大提高鎖的效率,自旋等待的時間明顯少于線程阻塞掛起和在喚醒所用的時間。
自旋鎖缺點:
如果線程占用鎖時間過長,線程在自旋的時候會長時間獲取不到鎖,造成CPU資源浪費。
二、CAS
2.1什么是CAS?
CAS 是樂觀鎖的一種實現方式,他采用的是自旋鎖(一直嘗試,直到成功)的思想,是一種輕量級的鎖機制。
CAS(Compare And Swap)指比較并交換。CAS算法CAS(V,E,N)包含三個參數,V表示要更新的變量,E表示預期的值,N表示新值。僅在V值等于E值,才會將V值設為N,如果V值和E值不同,表示有其他線程進行更新,當前線程什么都不做,不會被掛起,允許再次嘗試,直到成功。
從JDK 1.5開始提供了java.util.concurrent.atomic包,在該包中提供了許多基于CAS實現的原子操作類,用法方便,性能高效。我們以AtomicInteger為例進行分析CAS的JAVA實現代碼。
JDK1.7
public class AtomicInteger extends Number implements java.io.Serializable {private volatile int value;public final int get() {return value;}//JDK 1.7的源碼,由for的死循環實現,并且直接在AtomicInteger實現該方法,//JDK1.8后,直接調用getAndAddInt方法即可public final int getAndIncrement() {for(;;){ //CAS自旋,一直嘗試,直到成功int current=get();int next=current+1;if(compareAndSet(current,next)){return current;} }}public final boolean compareAndSet(int expect, int update) {return unsafe.compareAndSwapInt(this, valueOffset, expect, update);}}JDK1.8
//AtomicInteger中的方法public final int getAndIncrement() {return unsafe.getAndAddInt(this, valueOffset, 1);}//Unsafe中的方法public final int getAndAddInt(Object var1, long var2, int var4) {int var5;do {var5 = this.getIntVolatile(var1, var2);} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));return var5;}CAS是采用了樂觀鎖的思想,總是認為自己可以成功完成操作。有多個線程同時使用CAS操作同一個變量時只有一個會成功更新,其余均會失敗。
2.2ABA 問題
第一個線程從內存的V位置取出了A,第二個線程也從內存的V位置取出了A,先修改成B,然后又修改成了A,第一個線程在進行CAS操作時不會察覺到異常,雖然操作正常進行,但該數據已經發生過變化,某些應用場景下可能出現數據不一致的問題。
解決辦法:添加版本號,執行操作時加上一個版本號,版本號一致性可以進行操作,否則失敗。每次操作版本號增加,因為版本號只會增加不會減少,所以不會出現ABA問題。
例如:
1.線程1讀取A(1)
2.線程2讀取A(1),修改成B(2),又修改成A(3),
3.線程1讀取預期值,發現預期值A(3)和變量值A(1)不同,不進行操作。
總結
除了本文提到的鎖的類型,鎖從獲取資源的公平性角度可以分為公平鎖和非公平鎖,從是否共享資源的角度可分為共享鎖和獨占鎖,從鎖的狀態可分為偏向鎖、輕量級鎖和重量級鎖,后續會介紹這些鎖的特性。本文的重點CAS,理解了CAS就理解了樂觀鎖和自旋鎖的特點,對于比較并交換的過程一定要牢記于心。
總結
以上是生活随笔為你收集整理的CAS操作原理与实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深度聚类方法之对比聚类(Contrast
- 下一篇: 【python】将多个tsv文件合并到e