Java記憶體模型相關知識總結
【1】CPU和快取的一致性
我們應該都知道,計算機在執行程式的時候,每條指令都是在CPU中執行的,而執行的時候,又免不了要和資料打交道。而計算機上面的資料,是存放在主存當中的,也就是計算機的實體記憶體啦。
剛開始,還相安無事的,但是隨著CPU技術的發展,CPU的執行速度越來越快。而由於記憶體的技術並沒有太大的變化,所以從記憶體中讀取和寫入資料的過程和CPU的執行速度比起來差距就會越來越大,這就導致CPU每次操作記憶體都要耗費很多等待時間。
所以,人們想出來了一個好的辦法,就是在CPU和記憶體之間增加快取記憶體。快取的概念大家都知道,就是儲存一份資料拷貝。他的特點是速度快,記憶體小,並且昂貴。
那麼,程式的執行過程就變成了:
當程式在執行過程中,會將運算需要的資料從主存複製一份到CPU的快取記憶體當中,那麼CPU進行計算時就可以直接從它的快取記憶體讀取資料和向其中寫入資料,當運算結束之後,再將快取記憶體中的資料重新整理到主存當中。
在CPU和主存之間增加快取,在多執行緒場景下就可能存在快取一致性問題,也就是說,在多核CPU中,每個核的自己的快取中,關於同一個資料的快取內容可能不一致。
【2】處理器優化和指令重排
上面提到在在CPU和主存之間增加快取,在多執行緒場景下會存在快取一致性問題。除了這種情況,還有一種硬體問題也比較重要。那就是為了使處理器內部的運算單元能夠儘量的被充分利用,處理器可能會對輸入程式碼進行亂序執行處理。這就是處理器優化。
除了現在很多流行的處理器會對程式碼進行優化亂序處理,很多程式語言的編譯器也會有類似的優化,比如Java虛擬機器的即時編譯器(JIT)也會做指令重排。
可想而知,如果任由處理器優化和編譯器對指令重排的話,就可能導致各種各樣的問題。
解決方法:記憶體屏障
【3】什麼是Java記憶體模型
記憶體模型
為了保證共享記憶體的正確性(可見性、有序性、原子性),記憶體模型定義了共享記憶體系統中多執行緒程式讀寫操作行為的規範。通過這些規則來規範對記憶體的讀寫操作,從而保證指令執行的正確性。
Java記憶體模型(Java Memory Model,JMM)是java虛擬機器規範定義的,用來遮蔽掉java程式在各種不同的硬體和作業系統對記憶體的訪問的差異,這樣就可以實現java程式在各種不同的平臺上都能達到記憶體訪問的一致性。
Java記憶體模型的主要目標是定義程式中變數的訪問規則。即在虛擬機器中將變數儲存到主記憶體或者將變數從主記憶體取出這樣的底層細節。需要注意的是這裡的變數跟我們寫java程式中的變數不是完全等同的。這裡的變數是指例項欄位,靜態欄位,構成陣列物件的元素,但是不包括區域性變數和方法引數(因為這是執行緒私有的)。
Java記憶體模型中涉及到的概念有:
主記憶體:java虛擬機器規定所有的變數(不是程式中的變數)都必須在主記憶體中產生。可以與前面說的物理機的主記憶體相比,只不過物理機的主記憶體是整個機器的記憶體,而虛擬機器的主記憶體是虛擬機器記憶體中的一部分。
工作記憶體:java虛擬機器中每個執行緒都有自己的工作記憶體,該記憶體是執行緒私有的。可以與前面說的快取記憶體相比。執行緒的工作記憶體儲存了執行緒需要的變數在主記憶體中的副本。虛擬機器規定,執行緒對主記憶體變數的修改必須線上程的工作記憶體中進行,不能直接讀寫主記憶體中的變數。不同的執行緒之間也不能相互訪問對方的工作記憶體。如果執行緒之間需要傳遞變數的值,必須通過主記憶體來作為中介進行傳遞。
工作記憶體和主記憶體的劃分和 Java 堆,棧,方法區的劃分不同,兩者基本沒有關係,如果勉強對應,則主記憶體可理 解為堆中例項資料部分,工作記憶體則對應棧中部分割槽域
【4】volatile的記憶體語義
volatile寫的記憶體語義:
當寫一個變數的時候,JMM會把該執行緒的私有記憶體中的共享變數值更新到主記憶體中,並將其他執行緒中的值置為無效的;
volatile讀的記憶體語義:
當讀一個變數的時候,JMM會先判斷是否私有空間內的值是否失效,若失效,執行緒接下來會從主存中讀取變數。
【5】鎖的記憶體語義
當執行緒釋放鎖時,JMM會把該執行緒對應的本地記憶體中的共享變數重新整理到主記憶體中。
當執行緒獲取鎖時,JMM會把該執行緒對應的本地記憶體置為無效。從而使得被監視器保護的臨界區程式碼必須要從主記憶體中去讀取共享變數。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。