JSR內存屏障:
- LoadLoad:對於這樣的語句
Load1;LoadLoad;Load2
,在Load2及後續的讀操作要讀取的數據被訪問前,保證Load1要讀取的數據被讀取完畢; - StoreStore:對於這樣的語句
Store1;StoreStore;Store2
,在Store2及後續的寫操作執行前,保證Store1的寫入操作對其他處理器可見; - LoadStore:對於這樣的語句
Load1;LoadStore;Store2
,在Store2及後續的寫入操作被刷出前,保證Load1要讀取的數據被讀取完畢; - StoreLoad:對於這樣的語句
Store1;StoreLoad;Load2
,在Load2及後續的讀操作要讀取的數據被訪問前,保證Store1的寫入操作對其他處理器可見;
as-if-serial:
不管如何重排序,單線程執行結果不會改變。在JVM層面volatile的實現細節特別保守,保證了內存可見性,並且成功防止指令重排序。如果是對對象加入volatile,是對該對象前後加入內存屏障,具體的實現細節如下所示:
StoreStoreBarrier
volatile 寫操作
StoreLoadBarrier
LoadLoadBarrier
volatile 讀操作
LoadStoreBarrier
happens-before原則:
happens-before原則是Java內存模型中定義的兩個操作之間的偏序關係。比如說操作A先行發生於操作B,那麼在B操作發生之前,A操作產生的“影響”都會被操作B感知到。這裏的影響是指修改了內存中的共享變量、發送了消息、調用了方法等。
- 程序順序規則: 一個線程中的每個操作,happens-before於該線程中的任意後續操作;
- 監視器鎖規則: 對每一個鎖的解鎖,happens-before於隨後對該鎖的加鎖;
- Volatile變量規則:對一個volatile域的寫,happens-before於任意後續對這個volatile域的讀;
- 線程啓動規則:Thread的start()方法先行發生於這個線程的每一個操作;
- 線程終止原則:線程的所有操作都先行於此線程的終止檢測,可以通過Thread.join()方法結束、Thread.isAlive()的返回值等手段檢測線程的終止;
- 線程中斷原則:對線程interrupt()方法的調用先行發生於被中斷線程的代碼檢測到中斷事件的發生,可以通過Thread.interrupt方法檢測線程是否中斷;
- 對象終結規則:一個對象的初始化完成先於發生它的finalize()方法的開始;
- 傳遞性: 如果A happens-before B, B happens-before C, 那麼A happens-before C;
volatile關鍵字修飾變量的特殊規則:
- 可見性:對一個volatile變量的讀,總是能看到(任意線程)對這個volatile變量最後的寫入。
- 原子性:對任意單個volatile變量的讀/寫具有原子性,但類似於volatile++這種複合操作不具有原子性。
final域的重排序規則:
- 在構造函數內對一個final域的寫入,與隨後把這個被構造對象的引用賦值給一個引用變量,這兩個操作之間不能重排序;
- 初次讀一個包含final域的對象的引用,與隨後初次讀這個final域,這兩個操作之間不能重排序;