java Unsafe類中compareAndSwap相關介紹
最近在看jdk7中java.util.concurrent下面的原始碼中,發現許多類中使用了Unsafe類中的方法來保證併發的安全性,而java 7 api中並沒有這個類的相關介紹,在網上查了許多資料,其中http://ifeve.com/sun-misc-unsafe/這個網站詳細的講解了Unsafe的相關用法,而下面是結合網站中的介紹和具體的AtomicInteger類來講解一下其相關的用法。
- private static final Unsafe unsafe = Unsafe.getUnsafe();
- private static final long valueOffset;
- static {
- try
{ - valueOffset = unsafe.objectFieldOffset
- (AtomicInteger.class.getDeclaredField("value"));
- } catch (Exception ex) { throw new Error(ex); }
- }
- private volatile int value;
首先可以看到AtomicInteger類在域中聲明瞭這兩個私有變數unsafe和valueOffset。其中unsafe例項採用Unsafe類中靜態方法getUnsafe()得到,但是這個方法如果我們寫的時候呼叫會報錯,因為這個方法在呼叫時會判斷類載入器,我們的程式碼是沒有“受信任”的,而在jdk原始碼中呼叫是沒有任何問題的;valueOffset這個是指類中相應欄位在該類的偏移量,在這裡具體即是指value這個欄位在AtomicInteger類的記憶體中相對於該類首地址的偏移量。
然後可以看一個有一個靜態初始化塊,這個塊的作用即是求出value這個欄位的偏移量。具體的方法使用的反射的機制得到value的Field物件,再根據objectFieldOffset這個方法求出value這個變數記憶體中在該物件中的偏移量。
volatile關鍵字保證了在多執行緒中value的值是可見的,任何一個執行緒修改了value值,會將其立即寫回記憶體當中
- public final int getAndSet(int newValue) {
- for (;;) {
- int current = get();
- if (compareAndSet(current, newValue))
- return
current; - }
- }
- public final boolean compareAndSet(int expect, int update) {
- return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
- }
getAndSet這個方法作用為將value值設定為newValue,並返回修改前的value值在for迴圈中,保證每次如果compareAndSet這個方法失敗之後,能重新進行嘗試,直到成功將value值設定為newValue。
compareAndSet這個方法主要呼叫unsafe.compareAndSwapInt這個方法,這個方法有四個引數,其中第一個引數為需要改變的物件,第二個為偏移量(即之前求出來的valueOffset的值),第三個引數為期待的值,第四個為更新後的值。整個方法的作用即為若呼叫該方法時,value的值與expect這個值相等,那麼則將value修改為update這個值,並返回一個true,如果呼叫該方法時,value的值與expect這個值不相等,那麼不做任何操作,並範圍一個false。
因此之所以在getAndSet方法中呼叫一個for迴圈,即保證如果呼叫compareAndSet這個方法返回為false時,能再次嘗試進行修改value的值,直到修改成功,並返回修改前value的值。
整個程式碼能保證在多執行緒時具有執行緒安全性,並且沒有使用java中任何鎖的機制,所依靠的便是Unsafe這個類中呼叫的該方法具有原子性,這個原子性的保證並不是靠java本身保證,而是靠一個更底層的與作業系統相關的特性實現。