1. 程式人生 > >java多執行緒程式設計(六)

java多執行緒程式設計(六)

java多執行緒程式設計(六)

   資料依賴性  

如果兩個操作訪問同一個變數,且這兩個操作中有一個為寫操作,此時這兩個操作之間就存在資料依賴性。資料依賴分為下列3種類型,如下表所示。

名稱 程式碼示例 說明
寫後讀
a=1; b=a;
寫一個變數後,再讀這個位置
寫後寫
a=1;a=2;
寫一個變數後,再寫這個變數
讀後寫
a=b;b=1;
讀一個變數之後,再寫這個變數

上面三種操作,只要重排序兩個操作的執行順序,程式的執行結果就會改變。

前面提到過,編譯器和處理器可能會對操作做重排序。編譯器和處理器在重排序時,會遵
守資料依賴性,編譯器和處理器不會改變存在資料依賴關係的兩個操作的執行順序。

這裡所說的資料依賴性僅針對單個處理器中執行的指令序列和單個執行緒中執行的操作,
不同處理器之間和不同執行緒之間的資料依賴性不被編譯器和處理器考慮。

2

as-if-serial語義

as-if-serial語義的意思是:不管怎麼重排序(編譯器和處理器為了提高並行度),(單執行緒)程式的執行結果不能被改變。編譯器、runtime和處理器都必須遵守as-if-serial語義。

為了遵守as-if-serial語義,編譯器和處理器不會對存在資料依賴關係的操作做重排序,
因為這種重排序會改變執行結果。但是,如果操作之間不存在資料依賴關係,這些操作可能
被編譯器和處理器重排序。為了具體說明,請看下面計算圓面積的程式碼示例。

double pi= 3.14;    //A
double r=1.0;       //B
double area=pi*r*r; //C

依賴關係如下:
在這裡插入圖片描述

在執行時,可以為A -B-C 或 B-A-C

as-if-serial語義把單執行緒程式保護了起來,遵守as-if-serial語義的編譯器、runtime和處理器
共同為編寫單執行緒程式的程式設計師建立了一個幻覺:單執行緒程式是按程式的順序來執行的。asif-serial
語義使單執行緒程式設計師無需擔心重排序會干擾他們,也無需擔心記憶體可見性問題。

3

程式順序規則:

根據happens-before的程式順序規則,上面計算圓的面積的示例程式碼存在3個happensbefore關係。

1)A happens-before B。

2)B happens-before C。

3)A happens-before C。

這裡的第3個happens-before關係,是根據happens-before的傳遞性推匯出來的。

這裡A happens-before B,但實際執行時B卻可以排在A之前執行(看上面的重排序後的執
行順序)。如果A happens-before B,JMM並不要求A一定要在B之前執行。JMM僅僅要求前一個
操作(執行的結果)對後一個操作可見,且前一個操作按順序排在第二個操作之前。這裡操作A
的執行結果不需要對操作B可見;而且重排序操作A和操作B後的執行結果,與操作A和操作B
按happens-before順序執行的結果一致。在這種情況下,JMM會認為這種重排序並不非法(not
illegal),JMM允許這種重排序。

在計算機中,軟體技術和硬體技術有一個共同的目標:在不改變程式執行結果的前提下,
儘可能提高並行度。編譯器和處理器遵從這一目標,從happens-before的定義我們可以看出,
JMM同樣遵從這一目標。