Java中CAS操作本身怎么保证原子性及其原理分析
Java中CAS操作是怎么保證原子性的?
在學習Java多線程時我們會接觸到CAS這樣一個概念,CAS其實就是Compare And Swap的一個縮寫。Compare And Swap,顧名思義就是比較并交換,其實就是把當前值與你預期的值進行一個比較,如果一樣再進行修改,否則不修改并返回失敗。這里我解釋一下,當前值與預期值的一個概念:多線程環境下很可能發生當我拿到一個值還沒修改的時候,別的線程已經把這個值修改掉了,這樣就會引發線程安全問題,所以CAS操作就是在修改前用一個當前值和期望值來進行比較,只有相等,即沒有其他線程修改過這個值的時候(也可能發生一個線程改了,又有一個線程又改回來的情況,CAS無法感知到這種操作,它還是會認為數據沒有發生變化而進行修改。這種情況可以利用AtomicStampedReference和AtomicMarkableReference解決,兩者根據應用場景不同一定區別,這里不做闡述),才進行修改,從而保證操作的原子性。
可以看到compareAndSet方法中的expect(期望值),update(修改的值)。
CAS本身操作的原子性
那么CAS這個操作本身又是怎么保證原子性的呢?可以想象:比較——修改這是兩個動作,可能我比較的時候它是一樣的,當我修改的時候它卻被別的線程修改了。這就涉及到CAS本身這個操作是原子的,也就是不被其他線程所干擾的。這是利用CPU的原語來實現的。我們知道Java方法無法直接訪問底層系統,需要通過本地(Native)方法來訪問,Unsafe相當于一個橋梁,基于該類可以連接底層的操作系統直接操作特定的內存數據,Unsafe類存在sun.misc包中,其內部方法操作可以像C指針一樣直接操作內存,因此Java中的CAS操作的執行依賴于Unsafe類的方法。(Unsafe類很重要!不知道的同學可以多去了解,建議自己利用反射獲取unsafe對象自己寫一些東西,比如自己寫一個原子類)
進入compareAndSet方法我們發現他返回的是unsafe的compareAndSwapInt方法:
進入Unsafe類的native方法compareAndSwapInt,既然是native方法,那就不涉及到Java的代碼了,調用UnSafe類中的CAS方法,也就是這個本地native方法,JVM會幫我們實現出CAS匯編指令,這是一種完全依賴于硬件的功能,通過它實現了原子操作,由于CAS是一種系統原語,原語屬于操作系統用于范疇,是由若干條指令組成,用于完成某個功能的一個過程,并且原語的執行必須是連續的,在執行過程中不允許被中斷,也就是說CAS是一條CPU的原子指令,不會造成所謂的數據不一致的問題,也就是說CAS是線程安全的。
注意Unsafe類的所有方法都是native修飾的,也就是說unsafe類中的方法都直接調用操作系統底層資源執行相應的任務。
變量valueOffset
表示該變量值在內存中的偏移地址,因為Unsafe就是根據內存偏移地址獲取數據的,這個變量我們在自己利用unsafe對象寫一些操作的時候會用到,其實Compare操作也是一個內存比較的過程。
附上一個自己寫的原子類:
import sun.misc.Unsafe;import java.lang.reflect.Field;class MyAtomicInteger {private volatile int value;private static final long valueOffset;static final Unsafe UNSAFE;static {try {Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");theUnsafe.setAccessible(true);Unsafe unsafe = (Unsafe) theUnsafe.get(null); //這個成員變量就是Unsafe類型UNSAFE = unsafe;} catch (NoSuchFieldException | IllegalAccessException e) {throw new Error(e);}}static {try {//獲取value的偏移量,用于Unsafe直接訪問該屬性valueOffset = UNSAFE.objectFieldOffset(MyAtomicInteger.class.getDeclaredField("value"));} catch (NoSuchFieldException e) {e.printStackTrace();;throw new RuntimeException(e);}}public int getValue() {return value;}public void increment(int amount){while (true){int prev = this.value;int next = prev - amount;//CASif (UNSAFE.compareAndSwapInt(this,valueOffset,prev,next)){break;}}} }?
?
以上只是個人學習中一些感悟與分享,如有錯誤歡迎指正與交流。
總結
以上是生活随笔為你收集整理的Java中CAS操作本身怎么保证原子性及其原理分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CAS操作以及ABA问题
- 下一篇: 8--风格迁移