Java內存模型Memory Model

  Java內存模型,Java Memory Model,我個人更喜歡“Java存儲模型”的譯法。

  介紹

  如前所述,JVM被設計成一臺抽象的虛擬計算機,JVM的併發問題及解決方案與物理計算機中的併發問題有很多相似之處。

  由於現代計算機的內存與CPU在運算速度上的巨大差別,通常會加入一層更接近CPU讀寫速度的高速緩存(Cache),將運算使用到的數據複製到Cache中,讓運算能加速進行,運算結束後再從Cache同步回內存之中。這個設計解決了速度的矛盾,也帶來了一個新的問題:緩存一致性。在多CPU系統中,每個CPU都有自己的Cache,它們共享同一主內存,當多個CPU的運算任務涉及同一塊內存區域時,就可能導致各自的Cache數據不一致。對此又設計了“緩存一致性協議”,如MESI,要求各個CPU在讀寫Cache時,都遵循這些協議進行操作,以解決緩存數據不一致的問題。“內存模型”(Memory Model),就是在特定的協議下,對特定的高速緩存讀寫訪問過程進行抽象。不同架構的物理機器擁有不一樣的內存模式,而Java虛擬機也有自己的內存模型,其基礎原理是共通的。

  此外,爲了充分利用CPU的運算單元,可能會對輸入代碼進行亂序執行優化,只保證執行結果的一致性,但不保證各語句的計算順序與輸入代碼一致。Java虛擬機的即時編譯器也有類似的指令重排序優化。

  Java語言規範中試圖定義一種Java內存模型,以實現Java程序在各種平臺上能達到一致的內存訪問效果,爲多線程的同步和避免數據爭用提供一套有效平衡高吞吐與一致性的保障機制。

  什麼是Java內存模型

  一個內存模型描述的是,給定程序的某個特定的執行軌跡(trace)是否是該程序的一個合法執行。Java內存模型檢查執行軌跡中的每次讀操作,以及根據特定規則,校驗該讀操作觀察到的寫是否合法。內存模型描述了一個程序的可預期行爲,具體實現時擁有充分的自由度去生成需要的代碼,只要其最終執行結果可經由內存模型進行推測。

  通俗地講,Java內存模型(JMM)定義了一系列規則,以確保某一線程的寫操作能正確呈現給其他線程。JMM並沒有描述多線程該如何執行,而是描述多線程允許的行爲。

  JMM規定了所有的共享變量都存儲在JVM的主內存中。每條線程有自己的工作內存,用於保存該線程用到的變量的主內存副本拷貝(具體實現通常不會拷貝整個對象),線程對變量的操作全部在工作內存中進行,不能直接讀寫主內存中的變量。不同的線程間也無法直接訪問對方的工作內存,線程間變量值的傳遞需要通過主內存來完成。

  關於主內存和工作內存之間的具體交互協議,即一個變量如何從主內存拷貝到工作內存、如何從工作內存同步回主內存之類的實現細節,JMM定義了8種操作(lock,unlock,read,load,use,assign,store,write),虛擬機實現時必須保證以上每一種操作都是原子的、不可再分的。

  共享變量/堆內存:能夠在線程間共享的內存稱作“共享內存或堆內存”。所有的實例域、靜態域以及數組元素都存儲在堆內存中。方法中的局部變量永遠不會被線程間共享,也不會受內存模型影響。我們也無需關心線程內動作,每個單線程都應遵守正確的線程內語義。

  線程間的動作:線程間的動作是由某一線程執行,能被另一線程探測或直接影響的動作。包括:

  共享變量的讀/寫

  同步動作 (synchronization action)

  lock/unlock某個monitor;

  讀寫某個volatile變量

  啓動一個線程

  與外部交互的動作

  導致某個線程進入無限循環的動作(thread devergence action)

  延伸閱讀

  本文參考了《深入理解Java虛擬機》、《JSR-133-Memory Model》,有充裕時間的同學可以去完整過一遍,但原文有較多艱澀難懂之處。這裏做了較大的裁剪,隱藏更深一層的信息,以求對Java內存模型能有一個快速又不過於淺顯的瞭解。更多的概念和規則:

  緩存一致性,Cache Coherence,MESI協議

  Instruction Reorder,指令重排序

  Happens-Before 關係規則

  As-If-Serial ,線程內串行的語義

  Memory Barrier,內存屏障



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章