Atomic原子操作和volatile非原子性

首先,我們要理解什么叫原子操作,原子操作可以理解為:在多線程操作同一對象時,在非程序代碼加鎖狀況下,保證被操作對象是結(jié)果是符合預(yù)期的。

翻譯為人話就是:一個數(shù),很多線程去同時修改它,不加sync同步鎖,就可以保證修改結(jié)果是正確的。

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

CAS(Compare and swap):比較和替換是設(shè)計并發(fā)算法時用到的一種技術(shù)。簡單來說,比較和替換是使用一個期望值和一個變量的當(dāng)前值進(jìn)行比較,如果當(dāng)前變量的值與我們期望的值相等,就使用一個新值替換當(dāng)前變量的值。CAS是一種系統(tǒng)原語(所謂原語屬于操作系統(tǒng)用語范疇。原語由若干條指令組成的,用于完成一定功能的一個過程。primitive or atomic action 是由若干個機(jī)器指令構(gòu)成的完成某種特定功能的一段程序,具有不可分割性·即原語的執(zhí)行必須是連續(xù)的,在執(zhí)行過程中不允許被中斷)。CAS是Compare And Set的縮寫。CAS有3個操作數(shù),內(nèi)存值V,舊的預(yù)期值A(chǔ),要修改的新值B。當(dāng)且僅當(dāng)預(yù)期值A(chǔ)和內(nèi)存值V相同時,將內(nèi)存值V修改為B,否則什么都不做。

可以說,原子操作正是靠CAS算法保證的。可能有人會有疑問:CAS是比較替換算法,會不會同時有兩個線程同時比較且同時替換?答案當(dāng)然是:不會。

為什么不會?我們來看一下紅色字體的內(nèi)容,前方高能,需要操作系統(tǒng)的知識:

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

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

在x86 平臺上,CPU提供了在指令執(zhí)行期間對總線加鎖的手段。CPU芯片上有一條引線#HLOCK pin,如果匯編語言的程序中在一條指令前面加上前綴'LOCK',經(jīng)過匯編以后的機(jī)器代碼就使CPU在執(zhí)行這條指令的時候把#HLOCK pin的電位拉低,持續(xù)到這條指令結(jié)束時放開,從而把總線鎖住,這樣同一總線上別的CPU就暫時不能通過總線訪問內(nèi)存了,保證了這條指令在多處理器環(huán)境中的原子性。

所以,不會存在兩個線程同時比較、同時替換。另外,因為CAS是基于樂觀鎖的,也就是說當(dāng)寫入的時候,如果寄存器舊值已經(jīng)不等于現(xiàn)值,說明有其他CPU在修改,那就繼續(xù)嘗試。所以這就保證了操作的原子性。因此在大請求量的性能表現(xiàn)上,CAS樂觀鎖也是可以大大提高吞吐量的。

Atomic正是采用了CAS算法,所以可以在多線程環(huán)境下安全地操作對象。

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

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

下面解讀一下:

可見性:volatile修飾的對象在加載時會告知JVM,對象在CPU的緩存上對多個線程是同時可見的。

順序性:這里有JVM的內(nèi)存屏障的概念,簡單理解為:可以保證線程操作對象時是順序執(zhí)行的,詳細(xì)了解可以自行查閱。

一致性:可以保證多個線程讀取數(shù)據(jù)時,讀取到的數(shù)據(jù)是最新的。(注意讀取的是最新的數(shù)據(jù),但不保證寫回時不會覆蓋其他線程修改的結(jié)果)

基于上面的信息,大概可以初步了解volatile多線程下非原子性了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容