深入理解Atomic原子操作和volatile非原子性

NO IMAGE

首先,我們要理解什麼叫原子操作,原子操作可以理解為:在多執行緒操作同一物件時,在非程式程式碼加鎖狀況下,保證被操作物件是結果是符合預期的。

翻譯為人話就是:一個數,很多執行緒去同時修改它,不加sync同步鎖,就可以保證修改結果是正確的。

那它是如何保證的呢?我們先了解一個叫CAS的東西:

CAS(Compare and swap):比較和替換是設計併發演算法時用到的一種技術。簡單來說,比較和替換是使用一個期望值和一個變數的當前值進行比較,如果當前變數的值與我們期望的值相等,就使用一個新值替換當前變數的值。CAS是一種系統原語(所謂原語屬於作業系統用語範疇。原語由若干條指令組成的,用於完成一定功能的一個過程。primitive or atomic action 是由若干個機器指令構成的完成某種特定功能的一段程式,具有不可分割性·即原語的執行必須是連續的,在執行過程中不允許被中斷)。CAS是Compare And Set的縮寫。CAS有3個運算元,記憶體值V,舊的預期值A,要修改的新值B。當且僅當預期值A和記憶體值V相同時,將記憶體值V修改為B,否則什麼都不做。

可以說,原子操作正是靠CAS演算法保證的。可能有人會有疑問:CAS是比較替換演算法,會不會同時有兩個執行緒同時比較且同時替換?答案當然是:不會。

為什麼不會?我們來看一下紅色字型的內容,前方高能,需要作業系統的知識:

1、原語由若干條指令組成的,用於完成一定功能的一個過程。

2、即原語的執行必須是連續的,在執行過程中不允許被中斷。

在x86 平臺上,CPU提供了在指令執行期間對匯流排加鎖的手段。CPU晶片上有一條引線#HLOCK pin,如果組合語言的程式中在一條指令前面加上字首’LOCK’,經過彙編以後的機器程式碼就使CPU在執行這條指令的時候把#HLOCK pin的電位拉低,持續到這條指令結束時放開,從而把匯流排鎖住,這樣同一匯流排上別的CPU就暫時不能通過匯流排訪問記憶體了,保證了這條指令在多處理器環境中的原子性。

所以,不會存在兩個執行緒同時比較、同時替換。另外,因為CAS是基於樂觀鎖的,也就是說當寫入的時候,如果暫存器舊值已經不等於現值,說明有其他CPU在修改,那就繼續嘗試。所以這就保證了操作的原子性。因此在大請求量的效能表現上,CAS樂觀鎖也是可以大大提高吞吐量的。

Atomic正是採用了CAS演算法,所以可以在多執行緒環境下安全地操作物件。

總之,原子操作的基石是:CPU對匯流排加鎖,加鎖的方式叫:拉低電位(一串0101010100101呼嘯而過)。

然而,volatile是Java的關鍵字,官方解釋:volatile可以保證可見性、順序性、一致性。

下面解讀一下:

可見性:volatile修飾的物件在載入時會告知JVM,物件在CPU的快取上對多個執行緒是同時可見的。

順序性:這裡有JVM的記憶體屏障的概念,簡單理解為:可以保證執行緒操作物件時是順序執行的,詳細瞭解可以自行查閱。

一致性:可以保證多個執行緒讀取資料時,讀取到的資料是最新的。(注意讀取的是最新的資料,但不保證寫回時不會覆蓋其他執行緒修改的結果)

基於上面的資訊,大概可以初步瞭解volatile多執行緒下非原子性了。