AtomicInteger 源碼解析
AtomicInteger 是一個 Java concurrent 包提供的一個原子類,通過這個類可以對 Integer 進行一些原子操作。這個類的源碼比較簡單,主要是依賴於 sun.misc.Unsafe 提供的一些 native 方法保證操作的原子性。
Unsafe 可以直接操控內存和線程,是一個比較危險的類。在 Java 里我們是無法直接使用這個類的,得通過反射機制獲取。在這篇文章裡面我們也不會深入討論這個類,有興趣的讀者可以去看看它的 API 文檔:http://www.docjar.com/docs/api/sun/misc/Unsafe.html 。
我們會通過一個 Demo 來對 AtomicInteger 的源碼進行解析,同時簡單解釋一下其中涉及到的 Unsafe 類方法。
在這個 Demo 裡面,我們需要關注以下兩點:
AtomicInteger 在初始化的時候執行了哪些操作
getAndIncrement 是如何保證其操作的原子性的
AtomicInteger 在初始化的時候執行了哪些操作呢?由於代碼比較簡單,我們直接來看 AtomicInteger 的成員變數和靜態代碼塊
從上圖可以看出,AtomicInteger 主要有兩個靜態變數和一個成員變數,在初始化的時候會通過靜態代碼塊給 valueOffset 賦值。
value 這個不用說,就是用來存儲實際數值的;Unsafe 類我們之前有提到過,在這裡也不做贅述了。
那麼,valueOffset 這個靜態變數又是用來做什麼的呢?這時候我們就得看看它的賦值來源了。根據 API 文檔,Unsafe 的 objectFieldOffset 方法可以獲取成員屬性在內存中的地址相對於對象內存地址的偏移量。說得簡單點就是找到這個成員變數在內存中的地址,便於後續通過內存地址直接進行操作。
所以,valueOffset 其實就是用來定位 value,後續 Unsafe 類可以通過內存地址直接對 value 進行操作。
接著,我們再來看 AtomicInteger 的構造方法:
這是一個空方法,所以 AtomicInteger 在調用其默認構造方法的時候沒有執行任何操作,一切都是默認值。
所以,綜合靜態代碼和構造方法,AtomicInteger 在初始化的時候會定位其成員變數 value 的內存地址,後續通過內存地址直接對其進行操作。
了解了 AtomicInteger 的初始化邏輯,接下來我們再來看看 getAndIncrement 方法,可以看到還是依賴於 Unsafe 類。
我們再來看看 getAndAddInt 方法
這時候會發現它裡面又調用了 getIntVolatile 和 compareAndSwapInt 方法,而這兩個方法都是 native 方法,具體說明可以參照 Unsafe 的 API 文檔。
getIntVolatile 的主要作用是通過對象 var1 和成員變數相對於對象的內存偏移量 var2 來直接從內存地址中獲取成員變數的值,所以 var5 就是當前 AtomicInteger 的值。
而 compareAndSwapInt (簡稱CAS) 的主要邏輯如下:
通過對象 var1 和成員變數的內存偏移量 var2 來定位內存地址
判斷當前地址的值是否等於 var5
不等於:返回 false
等於:把當前地址的值替換成 var5 + var4 並返回 true
所以,綜合來說,getAndAddInt 方法的主要邏輯如下:
根據對象 var1 和內存偏移量 var2 來定位內存地址,獲取當前地址值
循環通過 CAS 操作更新當前地址值直到更新成功
返回舊值
以上便是 AtomicInteger 的部分源碼解析,其他源碼其實差別不大,主要都是依賴於 Unsafe 類進行操作,有興趣的可以自己去看一看。
TAG:皇家小黑屋 |