
我們知道保證線程安全的三個要素是原子性,可見性,有序性
CAS(Compare And Swap),指令級別保證某一內存地址V上的值的更新修改是一個原子操作
需要三個值:
內存地址V
該線程拿到的值A
期望更新后的值B
思路:如果地址V上的實際值和該線程拿到的值A相等,就給地址V賦給新值B,如果不是,不做任何操作。
循環(死循環,自旋)里不斷的進行CAS操作
JDK里為我們提供了這些原子操作類
AtomicBoolean,AtomicInteger,AtomicLong,AtomicReferenceAtomicIntegerArray,AtomicLongArray,AtomicReferenceArrayAtomicReference,AtomicMarkableReference,AtomicStampedReferenceAtomicReferenceFieldUpdater,AtomicIntegerFieldUpdater,AtomicLongFieldUpdater觀察這些類的源碼我們可以發現,CAS底層的原理實現都需要借助一個Unsafe類來實現,比如對于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();
}
}但是執行后發現,會報錯:
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) 查詢相關資料后發現,在使用該getUnsafe方法是,會判斷classLoader的類型,如果不是systemClassLoader則會拋出SecurityException(“Unsafe”)異常,所以用戶編寫的程序使用不了unsafe實例。
那如果我們想本地實現可以怎么辦呢?
Unsafe類本地使用方法下面給出一個本地使用Unsafe類初始化的方法,也是網上使用比較多的方法
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();
}
}正常執行,且輸出結果為:
true
this.value:10
false
this.value:10對于輸出結果,根據CAS原理我們分析可知,初始時,我們賦值value=5,那么第一個CAS操作時valueOffset地址對應的value值=5,與compareAndSwapInt參數里的期望值5匹配,因此CAS操作成功返回true,同時value值被賦為10。同理,第二次CAS操作取valueOffset地址對應的value=10,與方法中的期望值5不匹配,則CAS操作失敗返回false,此時value的值仍為10。
如果我們把第二次CAS操作的期望值設成10,那么最終的返回value值會為20。
true
this.value:10
true
this.value:20
你是否還在尋找穩定的海外服務器提供商?創新互聯www.cdcxhl.cn海外機房具備T級流量清洗系統配攻擊溯源,準確流量調度確保服務器高可用性,企業級服務器適合批量采購,新人活動首月15元起,快前往官網查看詳情吧
本文名稱:Java并發編程之CAS和Unsafe類本地使用方法-創新互聯
本文URL:http://www.js-pz168.com/article46/gihhg.html
成都網站建設公司_創新互聯,為您提供靜態網站、全網營銷推廣、云服務器、網站策劃、響應式網站、App設計
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯