保證Java中的原子操作方式有兩種方式
1 加鎖(能夠理解悲觀鎖機制)
2 CAS(能夠理解爲樂觀鎖機制)
CAS全稱是Compare and Swap 即比較並替換。在JDK中許多地方均可以看到它的身影,好比AQS同步組件,Atomic原子類操做等等都是以CAS實現的。其中java.util.concurrent 中的許多概念源自 Doug Lea 的 util.concurrent 庫,而Doug lea大神在同步組件中大量使用使用CAS技術鬼斧神工地實現了Java多線程的併發操做。java
在CAS中有三個參數:內存值V、舊的預期值A,要更新的值B。更新一個變量的時候,只有當變量的預期值A和內存地址V當中的實際值相同時,纔會將內存地址V對應的值修改成B。
來看一下Atomic包的源碼中是如何使用的CAS,並分析它的原理
AtomicInteger的成員變量多線程
// setup to use Unsafe.compareAndSwapInt for updates private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long valueOffset; static { try { valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } private volatile int value;
AtomicInteger的成員變量進行說明
1 Unsafe
Java語言不像C,C++那樣能夠直接訪問底層操做系統,可是JVM爲咱們提供了一個後門,這個後門就是unsafe。unsafe爲咱們提供了硬件級別的原子操做 。
2 valueOffset
至於valueOffset對象,是經過unsafe.objectFieldOffset方法獲得,所表明的是AtomicInteger對象value成員變量在內存中的偏移量。咱們能夠簡單地把valueOffset理解爲value變量的內存地址。
3 value
被volatile所修飾被volatile的特色就不在說明了上一篇文章已經提到過了。
AtomicInteger的compareAndSet()併發
/** * Atomically sets the value to the given updated value * if the current value {@code ==} the expected value. * * @param expect the expected value * @param update the new value * @return {@code true} if successful. False return indicates that * the actual value was not equal to the expected value. */ public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } //Unsafe.class public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
正是unsafe的compareAndSwapInt方法保證了Compare和Swap操做之間的原子性操做。this
1.ABA問題
由於CAS須要在操做值的時候,檢查值有沒有發生變化,若是沒有發生變化則更新,可是若是一個值原來是A,變成了B,又變成了A,那麼使用CAS進行檢查時會發現它的值沒有發生變化,可是實際上卻變化了。ABA問題的解決思路就是使用版本號。在變量前面追加上版本號,每次變量更新的時候把版本號加1,那麼A→B→A就會變成1A→2B→3A。從Java 1.5開始,JDK的Atomic包裏提供了一個類AtomicStampedReference來解決ABA問題。這個類compareAndSet方法的做用是首先檢查當前引用是否等於預期引用,而且檢查當前標誌是否等於預期標誌,若是所有相等,則以原子方式將該引用和該標誌的值設置爲給定的更新值。
2.循環時間長CPU開銷大
自旋CAS若是長時間不成功,會給CPU帶來很是大的執行開銷
3.只能保證一個共享變量的原子操作spa