學習Java記憶體模型JMM心得

學習Java記憶體模型JMM心得

有時候編譯器、處理器的優化會導致runtime與我們設想的不一樣,為此Java對編譯器和處理器做了一些限制,JAVA記憶體模型(JMM)將這些抽象出來,這樣編寫程式碼時就無需考慮那麼多底層細節,並保證“只要遵循JMM的規則編寫程式,其執行結果一定是正確的”。

JMM的抽象結構

在Java中,所有的例項、靜態變數儲存在堆記憶體中,堆記憶體是可以線上程間共享的,這部分也稱為共享變數。而區域性變數、方法定義引數、異常處理引數是在棧中的,棧記憶體不線上程間共享。

而由於編譯器、處理器的優化,會導致共享變數出現可見性問題,像在多核處理器中(multi-processor),執行緒可以在不同的處理器上執行,而處理器之間快取不一致,會使共享變數出現可見性問題,有可能兩個執行緒看到同一個變數不同值。

JMM將這些硬體做的優化抽象成每個執行緒都有一個本地記憶體。需要讀寫共享變數時,從主記憶體中拷貝一份到本地記憶體。當寫共享變數時,先寫到本地記憶體中去,在將來某個時間再重新整理到主記憶體中。當再次讀共享變數時,則只會從本地記憶體中讀取。

這樣執行緒間通訊就需要經過兩步:

寫執行緒:重新整理本地記憶體到主記憶體中去讀執行緒:從主記憶體讀取更新後的值

這樣在寫-讀之間就有一個延遲:本地記憶體什麼時候重新整理到主記憶體中去?導致可見性問題,不同執行緒可能看到的共享變數不一樣。

happens-before

從字面上看happens-before的意思是“發生在此之前”。這是java對程式執行順序制定的規則,實現同步必須遵循該規則。這樣程式設計師只需要寫出正確的同步程式,happens-before保證執行結果不會錯。

A happens-before B,不僅僅表示A在B之前執行,還意味著A的執行結果對B可見,這保證了可見性。

A happens-before B,A也不一定要在B之前執行,如果AB交替,執行結果任然正確,則允許編譯器、處理器進行優化重排序。所以只要程式結果正確,編譯器、處理器怎麼優化,怎麼重排序都沒問題,都是好的。

happens-before規則

程式順序規則:在一個執行緒中,前面的操作happens-before後面的操作鎖規則:對同一個鎖,解鎖happens-before加鎖 volatile域規則:寫volatile變數,happens-before後面任意一個讀這個volatile變數的操作傳遞性:A happens-before B,B happens-before C,則A happens-before C start()規則:如果執行緒A執行ThreadB.start() 那麼ThreadB.start() happens-before 執行緒B中任何操作 join()規則:如果執行緒A執行ThreadB.join(),那麼執行緒B中的所有操作happens-before ThreadB.join()

下面這個示例有助於理解happens-before


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

這裡有三個happens-before關係,規則1、2是程式順序規則,規則3是傳遞性規則推匯出來的:

A happens-before B B happens-before C A happens-before C

C依賴於A、B,但是A和B誰也不依賴。所以即使A和B重排序,執行結果也不會發生變化,這種重排序,JMM是執行的。

下面兩種執行順序的結果都是正確的。

以上就是我們給大家整理的關於Java記憶體模型JMM學習心得的全部內容,更多問題大家可以在下方留言討論,感謝你對指令碼之家的支援。