AtomicInteger 源碼分析閱讀
?
序
閱讀java源碼可能是每一個java程序員的必修課,只有知其所以然,才能更好的使用java,寫出更優美的程序,閱讀java源碼也為我們後面閱讀java框架的源碼打下了基礎。閱讀源代碼其實就像再看一篇長篇推理小說一樣,不能急於求成,需要慢慢品味才行。這一系列的文章,記錄了我閱讀源碼的收獲與思路,讀者也可以借鑒一下,也僅僅是借鑒,問渠那得清如許,絕知此事要躬行!要想真正的成為大神,還是需要自己親身去閱讀源碼而不是看幾篇分析源碼的博客就可以的。
正文
最近在看JAVA1.8線程池源碼的時候,發現對於AtomicInteger類的使用不太熟悉,所以就專門研究了一下,有一些收獲。AtomicInteger是juc(java.util.concurrent)包下提供的一個可以原子性操作Integer對象的類。通過它,我們可以很方便的對Integer進行線程安全的加、減、改值等操作。其原理是使用的CAS無鎖算法。
private static final long serialVersionUID = 6214790243416807050L;
// setup to use Unsafe.compareAndSwapInt for updates
//JAVA實現CAS算法的類,整個類有關線程安全的操作,都是借助它來實現。
private static final Unsafe unsafe = Unsafe.getUnsafe();
//變量value的內存首地址的偏移量。
private static final long valueOffset;
//靜態代碼塊,在類加載時運行
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField(value));
} catch (Exception ex) { throw new Error(ex); }
}
//存放int值
private volatile int value;
1.unsafe 其實就是負責與CAS相關的操作實現。
2.valueOffset的值是變量value的內存首地址的偏移量。,它在AtomicInteger被加載時就被賦值了。
3.value其實就是存放實際值的變量,它被volatile 關鍵字修飾,說明對於其他線程是可見的。
可能大家還是不大能夠了解valueOffset到底是個什麽東西,有什麽用,當時我也在這裏卡了很久,接下來我來講一下自己的分析過程。首先從字面意思來講,應該是和value有關的一個變量。再看它是由objectFieldOffset()這個方法的返回值進行賦值的。我們查看一下objectFieldOffset()的聲明定義:
發現並沒有任何描述,但是通過百度發現說是value在內存中首地址。出於嚴禁的角度,我就寫了一個測試來看看:
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,同時在調用的方法addAndGet()中打了斷點。
最後debug發現,兩個變量的valueOffset值都為12。說明valueOffset就是value內存首地址的偏移量。到這裏或許大家還想問,這個偏移應該是針對於什麽的偏移呢?你偏移量總得有個參照位置吧。這裏就要回到我們valueOffset的定義與賦值了。
private static final long valueOffset;
//靜態代碼塊,在類加載時運行
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField(value));
} catch (Exception ex) { throw new Error(ex); }
}
我們可以看到,valueOffset 是一個靜態常量,並且在類加載時就被賦值了。那麽這個類在編譯後的字節碼是一定的,但是存放對象的首地址是隨機的,所以這裏的偏移應該是相對於對象實例的首地址。如果大家看不明白,請看下面這幅圖,這幅圖簡介明了的描述了valueOffset 的含義。
再聯系到AtomicInteger在調用unsafe接口時,都將this和valueOffset 作為傳入參數(如下圖),我們可以了解到unsafe實現的CAS算法是依賴底層實現的(因為方法聲明有native關鍵字),我們為其提供具體的內存地址,即this+valueOffset ,就可以讓其找到要進行原子性操作的變量value,並進行修改。
?
AtomicInteger 源碼分析閱讀