我們知道保證線程安全的三個(gè)要素是原子性,可見性,有序性
CAS(Compare And Swap),指令級(jí)別保證某一內(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里為我們提供了這些原子操作類
AtomicBoolean
,AtomicInteger
,AtomicLong
,AtomicReference
AtomicIntegerArray
,AtomicLongArray
,AtomicReferenceArray
AtomicReference
,AtomicMarkableReference
,AtomicStampedReference
AtomicReferenceFieldUpdater
,AtomicIntegerFieldUpdater
,AtomicLongFieldUpdater
觀察這些類的源碼我們可以發(fā)現(xiàn),CAS底層的原理實(shí)現(xiàn)都需要借助一個(gè)Unsafe
類來實(shí)現(xiàn),比如對(duì)于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)行測(cè)試,代碼如下:
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;
}
// 測(cè)試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),會(huì)報(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方法是,會(huì)判斷classLoader的類型,如果不是systemClassLoader則會(huì)拋出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();
}
}
使用該初始化方法更新上面的測(cè)試代碼:
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
對(duì)于輸出結(jié)果,根據(jù)CAS原理我們分析可知,初始時(shí),我們賦值value=5,那么第一個(gè)CAS操作時(shí)valueOffset地址對(duì)應(yīng)的value值=5,與compareAndSwapInt
參數(shù)里的期望值5匹配,因此CAS操作成功返回true,同時(shí)value值被賦為10。同理,第二次CAS操作取valueOffset地址對(duì)應(yīng)的value=10,與方法中的期望值5不匹配,則CAS操作失敗返回false,此時(shí)value的值仍為10。
如果我們把第二次CAS操作的期望值設(shè)成10,那么最終的返回value值會(huì)為20。
true
this.value:10
true
this.value:20
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧
本文名稱:Java并發(fā)編程之CAS和Unsafe類本地使用方法-創(chuàng)新互聯(lián)
本文URL:http://jinyejixie.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)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容