1. 程式人生 > >Java內存模型(JMM)中的happens-before

Java內存模型(JMM)中的happens-before

ati img 執行 簡單 pen 性能 .cn style 程序員

  happens-before是JMM中最核心的概念,對於Java程序員來說,理解happens-before是理解JMM的關鍵 。

1.JMM的設計

  首先,來看看JMM的設計意圖。從JMM的設計者的角度,在設計JMM時,需要考慮兩個關鍵因素。

  (1)程序員對內存模型的使用。程序員希望內存模型易於理解、易於編程,程序員希望基於一個強內存模型來編寫代碼。

  (2)編譯器和處理器對內存模型的實現。編譯器和處理器希望內存模型對它們的束縛越少越好,這樣它們就可以做盡可能多的優化來提高性能。編譯器和處理器希望實現一個弱內存模型。

  由於這兩個因素互相矛盾,所以JSR-133專家組在設計JMM時的核心目標就是找到一個好 的平衡點:一方面,要為程序員提供足夠強的內存可見性保證;另一方面,對編譯器和處理器的限制要盡可能地放松。下面讓我們來看看JSR-133是如何實現這一目標的。

  

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

  上面計算圓的面積的示例代碼存在3個happens-before關系如下 :

  (1)A happens-before B

  (2)B happens-before C

  (3)A happens-before C

  在3個happens-before關系中,2和3是必須的,但1是不必要的。因此,JMM把happens-before 要求禁止的重排序分為了下面兩類 :

  □ 會改變程序執行結果的重排序。

  □ 不會改變程序執行結果的重排序。

  JMM對這兩種不同性質的重排序,采取了不同的策略,如下:

  □ 對於會改變程序執行結果的重排序,JMM要求編譯器和處理器必須禁止這種重排序。

  □ 對於不會改變程序執行結果的重排序,JMM對編譯器和處理器不做要求(JMM允許這種重排序) 。

  下圖是JMM的設計示意圖:

技術分享

  從上圖可以看出兩點,如下。

  □ JMM向程序員提供的happens-before規則能滿足程序員的需求。JMM的happens-before 規則不但簡單易懂,而且也向程序員提供了足夠強的內存可見性保證(有些內存可見性保證並不一定真是存在,比如上面的A happens-before B) 。

  □ JMM對編譯器和處理器的束縛已經盡可能少。從上面的分析可以看出,JMM其實是在遵循一個基本原則:只要不改變程序的執行結果(指的是單線程程序和正確同步的多線程程序),編譯器和處理器怎麽優化都行。例如,如果編譯器經過細致的分析後,認定一個鎖只會被單個線程訪問,那麽這個鎖可以被消除。再如,如果編譯器經過細致分析後,認定一個volatile變量只會被單個線程訪問,那麽編譯器可以把這個volatile變量當做是一個普通變量來對待。這些優化既不會改變程序的執行結果,又能提高程序的執行效率。

2.happens-before的定義

  

  

  

Java內存模型(JMM)中的happens-before