1. 程式人生 > >原子性、可見性、有序性與指令重排序

原子性、可見性、有序性與指令重排序

併發程式設計常有三個概念:

原子性:即一個操作或者多個操作 要麼全部執行並且執行的過程不會被任何因素打斷,要麼就都不執行。

可見性:指當多個執行緒訪問同一個變數時,一個執行緒修改了這個變數的值,其他執行緒能夠立即看得到修改的值

有序性:即程式執行的順序按照程式碼的先後順序執行

 

對於物理機記憶體模型

存在原子性,可實現可見性,但不滿足有序性:

會對指令進行重排序,即為了提高程式執行效率,可能會對輸入程式碼進行優化,它不保證程式中各個語句的執行先後順序同程式碼中的順序一致,但是它會保證程式最終執行結果和程式碼順序執行的結果是一致的。

 

java記憶體模型

原子性:

只保證了基本讀取和賦值是原子性操作

可見性:

當一個共享變數被volatile修飾時,它會保證修改的值會立即被更新到主存,當有其他執行緒需要讀取時,它會去記憶體中讀取新值。(注意,只能是變數)

另外,通過synchronized和Lock也能夠保證可見性,synchronized和Lock能保證同一時刻只有一個執行緒獲取鎖然後執行同步程式碼,並且在釋放鎖之前會將對變數的修改重新整理到主存當中。因此可以保證可見性。

有序性:

首先,Java允許編譯器和處理器對指令進行重排序,但是重排序過程不會影響到單執行緒程式的執行,卻會影響到多執行緒併發執行的正確性

volatile                  通過volatile關鍵字來保證一定的“有序性”

synchronized和Lock  通過synchronized和Lock來保證有序性,很顯然,synchronized和Lock保證每個時刻是有一個執行緒執行同步程式碼,相當於是讓執行緒順序執行同步程式碼,自然就保證了有序性。

先天的“有序性”         happens-before (先行發生)原則,如果兩個操作的執行次序無法從happens-before原則推匯出來,那麼它們就不能保證它們的有序性,虛擬機器可以隨意地對它們進行重排序。

 

happens-before 原則

1. 程式次序規則:一個執行緒內,按照程式碼順序,書寫在前面的操作先行發生於書寫在後面的操作

2. 鎖定規則:一個unLock操作先行發生於後面對同一個鎖額lock操作

3. volatile變數規則:對一個變數的寫操作先行發生於後面對這個變數的讀操作

4. 傳遞規則:如果操作A先行發生於操作B,而操作B又先行發生於操作C,則可以得出操作A先行發生於操作C

5. 執行緒啟動規則:Thread物件的start()方法先行發生於此執行緒的每個一個動作

6. 執行緒中斷規則:對執行緒interrupt()方法的呼叫先行發生於被中斷執行緒的程式碼檢測到中斷事件的發生

7. 執行緒終結規則:執行緒中所有的操作都先行發生於執行緒的終止檢測,我們可以通過Thread.join()方法結束、Thread.isAlive()的返回值手段檢測到執行緒已經終止執行

8. 物件終結規則:一個物件的初始化完成先行發生於他的finalize()方法的開始