序
閱讀java源碼可能是每一個java程序員的必修課,只有知其所以然,才能更好的使用java,寫出更優(yōu)美的程序,閱讀java源碼也為我們后面閱讀java框架的源碼打下了基礎(chǔ)。閱讀源代碼其實就像再看一篇長篇推理小說一樣,不能急于求成,需要慢慢品味才行。這一系列的文章,記錄了我閱讀源碼的收獲與思路,讀者也可以借鑒一下,也僅僅是借鑒,問渠那得清如許,絕知此事要躬行!要想真正的成為大神,還是需要自己親身去閱讀源碼而不是看幾篇分析源碼的博客就可以的。
正文
最近在看JAVA1.8線程池源碼的時候,發(fā)現(xiàn)對于AtomicInteger類的使用不太熟悉,所以就專門研究了一下,有一些收獲。AtomicInteger是juc(java.util.concurrent)包下提供的一個可以原子性操作Integer對象的類。通過它,我們可以很方便的對Integer進(jìn)行線程安全的加、減、改值等操作。其原理是使用的CAS無鎖算法。
private static final long serialVersionUID = 6214790243416807050L;
// setup to use Unsafe.compareAndSwapInt for updates
//JAVA實現(xiàn)CAS算法的類,整個類有關(guān)線程安全的操作,都是借助它來實現(xiàn)。
private static final Unsafe unsafe = Unsafe.getUnsafe();
//變量value的內(nèi)存首地址的偏移量。
private static final long valueOffset;
//靜態(tài)代碼塊,在類加載時運行
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
//存放int值
private volatile int value;
1.unsafe 其實就是負(fù)責(zé)與CAS相關(guān)的操作實現(xiàn),這里需要提一下的是Unsafe是不符合JAVA標(biāo)準(zhǔn)的,官方不推薦大家在編寫自己的中使用它,因為它引入了和C++中指針相似的東西,但可以借用java.util.concurrent.atomic包下的類來使用。
2.valueOffset的值是變量value的內(nèi)存首地址的偏移量。,它在AtomicInteger被加載時就被賦值了。
3.value其實就是存放實際值的變量,它被volatile 關(guān)鍵字修飾,說明對于其他線程是可見的。

發(fā)現(xiàn)并沒有任何描述,但是通過百度發(fā)現(xiàn)說是value在內(nèi)存中首地址。出于嚴(yán)禁的角度,我就寫了一個測試來看看:
public class Main {
public static void main(String[] args) {
AtomicInteger a=new AtomicInteger(1);
AtomicInteger b=new AtomicInteger(1);
int c=a.addAndGet(5);
b.addAndGet(4);
System.out.println(a.get());
System.out.println(c);
}
}
addAndGet()方法的定義與聲明

這個測試中,我實例化了兩個AtomicInteger 對象:a和b,同時在調(diào)用的方法addAndGet()中打了斷點。
最后debug發(fā)現(xiàn),兩個變量的valueOffset值都為12。說明valueOffset就是value內(nèi)存首地址的偏移量。到這里或許大家還想問,這個偏移應(yīng)該是針對于什么的偏移呢?你偏移量總得有個參照位置吧。這里就要回到我們valueOffset的定義與賦值了。
private static final long valueOffset;
//靜態(tài)代碼塊,在類加載時運行
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
我們可以看到,valueOffset 是一個靜態(tài)常量,并且在類加載時就被賦值了。那么這個類在編譯后的字節(jié)碼是一定的,但是存放對象的首地址是隨機(jī)的,所以這里的偏移應(yīng)該是相對于對象實例的首地址。如果大家看不明白,請看下面這幅圖,這幅圖簡介明了的描述了valueOffset 的含義。

再聯(lián)系到AtomicInteger在調(diào)用unsafe接口時,都將this和valueOffset 作為傳入?yún)?shù)(如下圖),我們可以了解到unsafe實現(xiàn)的CAS算法是依賴底層實現(xiàn)的(因為方法聲明有native關(guān)鍵字),我們?yōu)槠涮峁┚唧w的內(nèi)存地址,即this+valueOffset ,就可以讓其找到要進(jìn)行原子性操作的變量value,并進(jìn)行修改。

