我們知道保證線程安全的三個要素是原子性,可見性,有序性
CAS(Compare And Swap),指令級別保證某一內(nèi)存地址V上的值的更新修改是一個原子操作
需要三個值:
內(nèi)存地址V
該線程拿到的值A(chǔ)
期望更新后的值B
思路:如果地址V上的實際值和該線程拿到的值A(chǔ)相等,就給地址V賦給新值B,如果不是,不做任何操作。
循環(huán)(死循環(huán),自旋)里不斷的進行CAS操作
JDK里為我們提供了這些原子操作類
AtomicBoolean
,AtomicInteger
,AtomicLong
,AtomicReference
AtomicIntegerArray
,AtomicLongArray
,AtomicReferenceArray
AtomicReference
,AtomicMarkableReference
,AtomicStampedReference
AtomicReferenceFieldUpdater
,AtomicIntegerFieldUpdater
,AtomicLongFieldUpdater
觀察這些類的源碼我們可以發(fā)現(xiàn),CAS底層的原理實現(xiàn)都需要借助一個Unsafe
類來實現(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在本地操作,模仿了上面的代碼和初始化,嘗試在本地進行測試,代碼如下:
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),會報錯:
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實例。
那如果我們想本地實現(xiàn)可以怎么辦呢?
Unsafe類本地使用方法下面給出一個本地使用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原理我們分析可知,初始時,我們賦值value=5,那么第一個CAS操作時valueOffset地址對應(yīng)的value值=5,與compareAndSwapInt
參數(shù)里的期望值5匹配,因此CAS操作成功返回true,同時value值被賦為10。同理,第二次CAS操作取valueOffset地址對應(yīng)的value=10,與方法中的期望值5不匹配,則CAS操作失敗返回false,此時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海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧
本文名稱:Java并發(fā)編程之CAS和Unsafe類本地使用方法-創(chuàng)新互聯(lián)
本文URL:http://vcdvsql.cn/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è)計
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容