Volatile禁止指令重排序(三)

2022-01-10 03:14:40 字數 2420 閱讀 9477

計算機在執行程式時,為了提高效能,編譯器和處理器常常會對指令重排,一般分為以下三種:

源** -> 編譯器優化的重排 -> 指令並行的重排 -> 記憶體系統的重排 -> 最終執行指令
單執行緒環境裡面確保最終執行結果和**順序的結果一致

處理器在進行重排序時,必須要考慮指令之間的資料依賴性

多執行緒環境中線程交替執行,由於編譯器優化重排的存在,兩個執行緒中使用的變數能否保證一致性是無法確定的,結果無法**。

public void mysort()
按照正常單執行緒環境,執行順序是 1 2 3 4

但是在多執行緒環境下,可能出現以下的順序:

上述的過程就可以當做是指令的重排,即內部執行順序,和我們的**順序不一樣

但是指令重排也是有限制的,即不會出現下面的順序

因為處理器在進行重排時候,必須考慮到指令之間的資料依賴性

因為步驟 4:需要依賴於 y的申明,以及x的申明,故因為存在資料依賴,無法首先執行

int a,b,x,y = 0

執行緒1執行緒2

x = a;

y = b;

b = 1;

a = 2;

x = 0; y = 0

因為上面的**,不存在資料的依賴性,因此編譯器可能對資料進行重排

執行緒1執行緒2

b = 1;

a = 2;

x = a;

y = b;

x = 2; y = 1

這樣造成的結果,和最開始的就不一致了,這就是導致重排後,結果和最開始的不一樣,因此為了防止這種結果出現,volatile就規定禁止指令重排,為了保證資料的一致性

比如下面這段**

public class resortseqdemo 

public void method02() }}

我們按照正常的順序,分別呼叫method01() 和 method02() 那麼,最終輸出就是 a = 6

但是如果在多執行緒環境下,因為方法1 和 方法2,他們之間不能存在資料依賴的問題,因此原先的順序可能是

a = 1;

flag = true;

a = a + 5;

system.out.println("revalue:" + a);

但是在經過編譯器,指令,或者記憶體的重排後,可能會出現這樣的情況

flag = true;

a = a + 5;

system.out.println("revalue:" + a);

a = 1;

也就是先執行 flag = true後,另外乙個執行緒馬上呼叫方法2,滿足 flag的判斷,最終讓a + 5,結果為5,這樣同樣出現了資料不一致的問題

為什麼會出現這個結果:多執行緒環境中線程交替執行,由於編譯器優化重排的存在,兩個執行緒中使用的變數能否保證一致性是無法確定的,結果無法**。

這樣就需要通過volatile來修飾,來保證執行緒安全性

volatile實現禁止指令重排優化,從而避免了多執行緒環境下程式出現亂序執行的現象

首先了解乙個概念,記憶體屏障(memory barrier)又稱記憶體柵欄,是乙個cpu指令,它的作用有兩個:

由於編譯器和處理器都能執行指令重排的優化,如果在指令間插入一條memory barrier則會告訴編譯器和cpu,不管什麼指令都不能和這條memory barrier指令重排序,也就是說通過插入記憶體屏障禁止在記憶體屏障前後的指令執行重排序優化。 記憶體屏障另外乙個作用是重新整理出各種cpu的快取數,因此任何cpu上的執行緒都能讀取到這些資料的最新版本。

也就是過在volatile的寫 和 讀的時候,加入屏障,防止出現指令重排的

屏障型別

指令示例

說明loadload

load1;loadload;load2

保證load1的讀取操作在load2及後續讀取操作之前執行

storestore

store1;storestore;store2

在store2及其後的寫操作執行前,保證store1的寫操作已重新整理到主記憶體

loadstore

load1;loadstore;store2

在store2及其後的寫操作執行前,保證load1的讀操作已讀取結束

storeload

store1;storeload;load2

保證load1的寫操作已重新整理到主記憶體之後,load2及其後的讀操作才能執行

工作記憶體與主記憶體同步延遲現象導致的可見性問題

對於指令重排導致的可見性問題和有序性問題

Volatile禁止指令重排

你寫的程式,計算機並不是按照你寫的那樣去執行的。源 編譯器優化的重排 指令並行可能會重排 記憶體系統可能會重排 執行 處理器在進行指令重排的時候,考慮,資料之間的依賴性!指令重排 不會造成影響的例子 int x 1 1int y 2 2x x 5 3y x x 4我們所期望的 1234 執行的時候可...

volatile的指令重排細節

volatile禁止重排優化 volatile關鍵字另乙個作用就是禁止指令重排優化,從而避免多執行緒環境下程式出現亂序執行的現象,關於指令重排優化前面已詳細分析過,這裡主要簡單說明一下volatile是如何實現禁止指令重排優化的。先了解乙個概念,記憶體屏障 memory barrier 記憶體屏障,...

重排序與volatile

為了提高編譯器和處理器的能力,對 編譯執行順序進行修改 a和b沒有依賴關係,編譯時可能會是b先執行在執行a int a 1 int b 2 下面由於b依賴於a,所以不會進行重排序 int a 1 int b a 1當乙個執行緒對共享變數進行修改,其他執行緒可以立即知道新的共享變數的值,防止重排序 每...