日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java中的CAS和原子类的实现

發布時間:2024/9/30 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java中的CAS和原子类的实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

什么是CAS

????CAS的全稱為Compare-And-Swap,直譯就是對比交換。是一條CPU的原子指令,其作用是讓CPU先進行比較兩個值是否相等,然后原子地更新某個位置的值,經過調查發現,其實現方式是基于硬件平臺的匯編指令,就是說CAS是靠硬件實現的,JVM只是封裝了匯編調用,那些AtomicInteger類便是使用了這些封裝后的接口。
????簡單解釋:CAS操作需要輸入兩個數值,一個舊值(期望操作前的值)和一個新值,在操作期間先比較下在舊值有沒有發生變化,如果沒有發生變化,才交換成新值,發生了變化則不交換。
????CAS操作是原子性的,所以多線程并發使用CAS更新數據時,可以不使用鎖。JDK中大量使用了CAS來更新數據而防止加鎖(synchronized 重量級鎖)來保持原子更新。
????相信sql大家都熟悉,類似sql中的條件更新一樣:update set id=3 from table where id=2。因為單條sql執行具有原子性,如果有多個線程同時執行此sql語句,只有一條能更新成功。

????如果不使用CAS,在高并發下,多線程同時修改一個變量的值我們需要synchronized加鎖(可能有人說可以用Lock加鎖,Lock底層的AQS也是基于CAS進行獲取鎖的)。

public class Test {private int i=0;public synchronized int add(){return i++;} }

????java中為我們提供了AtomicInteger 原子類(底層基于CAS進行更新數據的),不需要加鎖就在多線程并發場景下實現數據的一致性。

public class Test {private AtomicInteger i = new AtomicInteger(0);public int add(){return i.addAndGet(1);} }

java.util.concurrent包都中的實現類都是基于volatile和CAS來實現的。尤其java.util.concurrent.atomic包下的原子類。

簡單介紹下volatile特性:
1. 內存可見性(當一個線程修改volatile變量的值時,另一個線程就可以實時看到此變量的更新值)
2. 禁止指令重排(volatile變量之前的變量執行先于volatile變量執行,volatile之后的變量執行在volatile變量之后)

AtomicInteger 源碼解析

public class AtomicInteger extends Number implements java.io.Serializable {private static final Unsafe unsafe = Unsafe.getUnsafe();private static final long valueOffset;static {try {//用于獲取value字段相對當前對象的“起始地址”的偏移量valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));} catch (Exception ex) { throw new Error(ex); }}private volatile int value;//返回當前值public final int get() {return value;}//遞增加detlapublic final int getAndAdd(int delta) {//三個參數,1、當前的實例 2、value實例變量的偏移量 3、當前value要加上的數(value+delta)。return unsafe.getAndAddInt(this, valueOffset, delta);}//遞增加1public final int incrementAndGet() {return unsafe.getAndAddInt(this, valueOffset, 1) + 1;} ... }

我們可以看到 AtomicInteger 底層用的是volatile的變量和CAS來進行更改數據的。
volatile保證線程的可見性,多線程并發時,一個線程修改數據,可以保證其它線程立馬看到修改后的值
CAS 保證數據更新的原子性。

Unsafe源碼解析

下面分析下Unsafe 類中的實現。代碼反編譯出來的。

public final int getAndAddInt(Object paramObject, long paramLong, int paramInt){int i;doi = getIntVolatile(paramObject, paramLong);while (!compareAndSwapInt(paramObject, paramLong, i, i + paramInt));return i;}public final long getAndAddLong(Object paramObject, long paramLong1, long paramLong2){long l;dol = getLongVolatile(paramObject, paramLong1);while (!compareAndSwapLong(paramObject, paramLong1, l, l + paramLong2));return l;}public final int getAndSetInt(Object paramObject, long paramLong, int paramInt){int i;doi = getIntVolatile(paramObject, paramLong);while (!compareAndSwapInt(paramObject, paramLong, i, paramInt));return i;}public final long getAndSetLong(Object paramObject, long paramLong1, long paramLong2){long l;dol = getLongVolatile(paramObject, paramLong1);while (!compareAndSwapLong(paramObject, paramLong1, l, paramLong2));return l;}public final Object getAndSetObject(Object paramObject1, long paramLong, Object paramObject2){Object localObject;dolocalObject = getObjectVolatile(paramObject1, paramLong);while (!compareAndSwapObject(paramObject1, paramLong, localObject, paramObject2));return localObject;}

從源碼中發現,內部使用自旋的方式進行CAS更新(while循環進行CAS更新,如果更新失敗,則循環再次重試)。

又從Unsafe類中發現,原子操作其實只支持下面三個方法。

public final native boolean compareAndSwapObject(Object paramObject1, long paramLong, Object paramObject2, Object paramObject3);public final native boolean compareAndSwapInt(Object paramObject, long paramLong, int paramInt1, int paramInt2);public final native boolean compareAndSwapLong(Object paramObject, long paramLong1, long paramLong2, long paramLong3);

我們發現Unsafe只提供了3種CAS方法:compareAndSwapObject、compareAndSwapInt和compareAndSwapLong。都是native方法。

AtomicBoolean 源碼解析

public class AtomicBoolean implements java.io.Serializable {private static final Unsafe unsafe = Unsafe.getUnsafe();private static final long valueOffset;static {try {valueOffset = unsafe.objectFieldOffset(AtomicBoolean.class.getDeclaredField("value"));} catch (Exception ex) { throw new Error(ex); }}private volatile int value;public AtomicBoolean(boolean initialValue) {value = initialValue ? 1 : 0;}public final boolean compareAndSet(boolean expect, boolean update) {int e = expect ? 1 : 0;int u = update ? 1 : 0;return unsafe.compareAndSwapInt(this, valueOffset, e, u);}... }

從AtomicBoolean源碼,發現他底層也是使用volatile類型的int 變量,跟AtomicInteger 實現方式一樣,只不過是把Boolean轉換成 0和1進行操作。

所以原子更新char、float和double變量也可以轉換成int 或long來實現CAS的操作。

CAS缺點

  • ABA問題。因為CAS需要在操作值的時候檢查下值有沒有發生變化,如果沒有發生變化則更新,但是如果一個值原來是A,變成了B,又變成了A,那么使用CAS進行檢查時會發現它的值沒有發生變化,但是實際上卻變化了。ABA問題的解決思路就是使用版本號。在變量前面追加上版本號,每次變量更新的時候把版本號加一,那么A-B-A 就會變成1A-2B-3A。
    從Java1.5開始JDK的atomic包里提供了一個類AtomicStampedReference來解決ABA問題。這個類的compareAndSet方法作用是首先檢查當前引用是否等于預期引用,并且當前標志是否等于預期標志,如果全部相等,則以原子方式將該引用和該標志的值設置為給定的更新值。
  • 循環時間長開銷大。自旋CAS如果長時間不成功,會給CPU帶來非常大的執行開銷。
  • 本人簡書blog地址:http://www.jianshu.com/u/1f0067e24ff8????
    點擊這里快速進入簡書

    總結

    以上是生活随笔為你收集整理的java中的CAS和原子类的实现的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。