volatile

volatile關(guān)鍵字
private volatile int count;

volatile關(guān)鍵字主要有三方面作用:
1.實現(xiàn)1ong/ double類型變量的原子操作
2.防止指令重排序
3.實現(xiàn)變量的可見性

volatile double a = 1.0
例子: 比如修改某個數(shù)的低32位,另一個線程修改高32位, 第3個線程讀取錯誤

當(dāng)使用volatile修飾變量時,應(yīng)用就不會從寄存器中獲取該變量的值,而是從內(nèi)存(高速緩存)中獲取。

volatile與鎖類似的地方有兩點(diǎn):
1.確保變量的內(nèi)存可見性
2.防止指令重排序

volatile可以確保對變量寫操作的原子性,但不具備排他性
原子性: 指一條CPU指令
排他性: 只有一個線程能進(jìn)入, 其它線程進(jìn)入不了,需要等當(dāng)前線程執(zhí)行完才能進(jìn)入

另外的重要一點(diǎn)在于:使用鎖可能會導(dǎo)致線程的上下文切換(內(nèi)核態(tài)與用戶態(tài)之間的切換),但使用volatile并不會出現(xiàn)這種情況

volatile int count = 1;
volatile boolean flag = false;

如果要實現(xiàn)volatile寫操作的原子性,那么在等號右側(cè)的賦值變量中就不能出現(xiàn)被多線程所共享的變量,哪怕這個變量也是個volatile也不可以。
int a = b + 2; //不適用, 右邊有變量b 它無法保證原子性(需要先讀取變量b,再加2)

volatile Date date = new Date();


防止指令重排序與實現(xiàn)變量的可見性都是通過-種手段來實現(xiàn)的:內(nèi)存屏障(memory barrier)

int a= 1;
String s = "hello";

內(nèi)存屏障(Release Barrier,釋放屏障)

volatile boolean v = false; // 寫入操作

內(nèi)存屏障(Store Barrier, 存儲屏障)

Release Barrier: 防止"下面"的volatile與上面的所有操作的指令重排序。
Store Barrier: 重要作用是刷新處理器緩存,結(jié)果是可以確保該存儲屏障之前一切的操作所生成的結(jié)果對于其他處理器來說都可見。

內(nèi)存屏障(Load Barrier, 加載屏障)

boolean v1 = V; //讀取

內(nèi)存屏障(Acquire Barrier, 獲取屏障)

int a= 1;
String s = "hello";

Load Barrier: 可以刷新處理器緩存,同步其他處理器對該volatile變量的修改結(jié)果。
Acquire Barrier: 可以防止"上面"的volatile讀取操作與下面的所有操作語句的指令重排序。

對于volatile關(guān)鍵字變量的讀寫操作,本質(zhì)上都是通過內(nèi)存屏障來執(zhí)行的。
內(nèi)存屏障兼具了兩方面能力: 1.防止指令重排序,2. 實現(xiàn)變量內(nèi)存的可見性。

1.對于讀取操作來說,volatile可以確保該操作與其"后面"的所有讀寫操作都不會進(jìn)行指令重排序
2.對于修改操作來說,volatile可以確保該操作與其"上面"的所有讀寫操作都不會進(jìn)行指令重排序

以上介紹的volatile主要是針對原生類型的操作, 對引用類型是不適用的
///////////////////////////////

ArrayList


volatile 與 鎖 的一些比較

鎖同樣具備變量內(nèi)存可見性與防止指令重排序的功能。
monitorenter
內(nèi)存屏障(Acquire Barrier, 獲取屏障)

..............................

內(nèi)存屏障(Release Barrier,釋放屏障)
monitorexit


happen-before重要規(guī)則:

1.順序執(zhí)行規(guī)則(限定在單個線程上的) :該線程的每個動作都happen-before它的后面的動作。
2.隱式鎖(monitor) 規(guī)則: unlock happen-before lock, 之前的線程對于同步代碼塊的所有執(zhí)行結(jié)果對于后續(xù)獲取鎖的線程來說都是可見的。

  1. volatile讀寫規(guī)則:對于-個volatile變量的寫操作一定會happen-before后續(xù)對該變量的讀操作。
    4.多線程的啟動規(guī)則: Thread對象的start方法happen-before該線程run方法中的任何一個動作,包括在其中啟動的任何子線程。
    5.多線程的終止規(guī)則: 一個線程啟動了一個子線程,并且調(diào)用了子線程的join方法等待其結(jié)束,那么當(dāng)子線程結(jié)束后,
    父線程的接下來的所有操作都可以看到子線程run方法中的執(zhí)行結(jié)果。
    6.線程的中斷規(guī)則:可以調(diào)用interrupt方法來中斷線程,這個調(diào)用happen-before對該線程中斷的檢查(isInterrupted) 。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容