Java并發(fā)編程之CAS和Unsafe類本地使用方法-創(chuàng)新互聯(lián)

Java 并發(fā)編程之CAS 和 Unsafe類本地使用方法

成都創(chuàng)新互聯(lián)公司是一家企業(yè)級云計(jì)算解決方案提供商,超15年IDC數(shù)據(jù)中心運(yùn)營經(jīng)驗(yàn)。主營GPU顯卡服務(wù)器,站群服務(wù)器,成都聯(lián)通服務(wù)器托管,海外高防服務(wù)器,大帶寬服務(wù)器,動態(tài)撥號VPS,海外云手機(jī),海外云服務(wù)器,海外服務(wù)器租用托管等。文章目錄
  • Java 并發(fā)編程之CAS 和 Unsafe類本地使用方法
    • CAS原理與Unsafe類
    • Unsafe類本地使用方法

CAS原理與Unsafe類

我們知道保證線程安全的三個(gè)要素是原子性,可見性,有序性

CAS(Compare And Swap),指令級別保證某一內(nèi)存地址V上的值的更新修改是一個(gè)原子操作
需要三個(gè)值:

  • 內(nèi)存地址V

  • 該線程拿到的值A(chǔ)

  • 期望更新后的值B

思路:如果地址V上的實(shí)際值和該線程拿到的值A(chǔ)相等,就給地址V賦給新值B,如果不是,不做任何操作。
循環(huán)(死循環(huán),自旋)里不斷的進(jìn)行CAS操作

JDK里為我們提供了這些原子操作類

  • 更新基本類型類:AtomicBooleanAtomicInteger,AtomicLong,AtomicReference
  • 更新數(shù)組類:AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray
  • 更新引用類型:AtomicReferenceAtomicMarkableReference,AtomicStampedReference
  • 原子更新字段類:AtomicReferenceFieldUpdater,AtomicIntegerFieldUpdater,AtomicLongFieldUpdater

觀察這些類的源碼我們可以發(fā)現(xiàn),CAS底層的原理實(shí)現(xiàn)都需要借助一個(gè)Unsafe類來實(shí)現(xiàn),比如對于AtomicInteger類的compareAndSet方法:

public final boolean compareAndSet(int expect, int update) {return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

代碼中unsafe變量的初始化:

private static final Unsafe unsafe = Unsafe.getUnsafe();

于是,為了嘗試使用CAS在本地操作,模仿了上面的代碼和初始化,嘗試在本地進(jìn)行測試,代碼如下:

public class CASTest {static volatile long valueOffset;
    // Unsafe類初始化
    static Unsafe unsafe = sun.misc.Unsafe.getUnsafe();


    static {//        initUnsafe();
        try {valueOffset = unsafe.objectFieldOffset
                    (CASTest.class.getDeclaredField("value"));
        } catch (Exception ex) {throw new Error(ex); }
    }
    
    private static void initUnsafe() {try {Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            Unsafe unsafe1 =  (Unsafe) f.get(null);
            unsafe = unsafe1;
        } catch (IllegalAccessException e) {e.printStackTrace();
        } catch (NoSuchFieldException e) {e.printStackTrace();
        }
    }
    
    
    volatile int value;

    public CASTest(int value) {this.value = value;
    }
	
    // 測試cas操作
    public void cas() {System.out.println(unsafe.compareAndSwapInt(this, valueOffset , 5, 10));
        System.out.println("this.value:" + this.value);
        System.out.println(unsafe.compareAndSwapInt(this, valueOffset , 5, 20));
        System.out.println("this.value:" + this.value);
    }
    public static void main(String[] args) {new CASTest(5).cas();
    }
}

但是執(zhí)行后發(fā)現(xiàn),會報(bào)錯(cuò):

Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.SecurityException: Unsafe
	at sun.misc.Unsafe.getUnsafe(Unsafe.java:90)
	at com.lagou.concurrent.demo.test.CASTest.(CASTest.java:9)

查詢相關(guān)資料后發(fā)現(xiàn),在使用該getUnsafe方法是,會判斷classLoader的類型,如果不是systemClassLoader則會拋出SecurityException(“Unsafe”)異常,所以用戶編寫的程序使用不了unsafe實(shí)例。

那如果我們想本地實(shí)現(xiàn)可以怎么辦呢?

Unsafe類本地使用方法

下面給出一個(gè)本地使用Unsafe類初始化的方法,也是網(wǎng)上使用比較多的方法

private static void initUnsafe() {try {Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            Unsafe unsafe1 =  (Unsafe) f.get(null);
            unsafe = unsafe1;
        } catch (IllegalAccessException e) {e.printStackTrace();
        } catch (NoSuchFieldException e) {e.printStackTrace();
        }
    }

使用該初始化方法更新上面的測試代碼:

public class CASTest {static volatile long valueOffset;
    static Unsafe unsafe;


    static {initUnsafe();
        try {valueOffset = unsafe.objectFieldOffset
                    (CASTest.class.getDeclaredField("value"));
        } catch (Exception ex) {throw new Error(ex); }
    }

    private static void initUnsafe() {try {Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            Unsafe unsafe1 =  (Unsafe) f.get(null);
            unsafe = unsafe1;
        } catch (IllegalAccessException e) {e.printStackTrace();
        } catch (NoSuchFieldException e) {e.printStackTrace();
        }
    }
    volatile int value;

    public CASTest(int value) {this.value = value;
    }

    public void cas() {System.out.println(unsafe.compareAndSwapInt(this, valueOffset , 5, 10));
        System.out.println("this.value:" + this.value);
        System.out.println(unsafe.compareAndSwapInt(this, valueOffset , 5, 20));
        System.out.println("this.value:" + this.value);
    }
    public static void main(String[] args) {new CASTest(5).cas();
    }
}

正常執(zhí)行,且輸出結(jié)果為:

true
this.value:10
false
this.value:10

對于輸出結(jié)果,根據(jù)CAS原理我們分析可知,初始時(shí),我們賦值value=5,那么第一個(gè)CAS操作時(shí)valueOffset地址對應(yīng)的value值=5,與compareAndSwapInt參數(shù)里的期望值5匹配,因此CAS操作成功返回true,同時(shí)value值被賦為10。同理,第二次CAS操作取valueOffset地址對應(yīng)的value=10,與方法中的期望值5不匹配,則CAS操作失敗返回false,此時(shí)value的值仍為10。

如果我們把第二次CAS操作的期望值設(shè)成10,那么最終的返回value值會為20。

true
this.value:10
true
this.value:20

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧

本文名稱:Java并發(fā)編程之CAS和Unsafe類本地使用方法-創(chuàng)新互聯(lián)
本文URL:http://bm7419.com/article46/gihhg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供靜態(tài)網(wǎng)站全網(wǎng)營銷推廣、云服務(wù)器、網(wǎng)站策劃、響應(yīng)式網(wǎng)站、App設(shè)計(jì)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)