1. 程式人生 > >執行緒安全性問題之JMM記憶體模型

執行緒安全性問題之JMM記憶體模型

由於在硬體層面存在快取一致性問題,而快取一致性會導致可見性問題,處理器的亂序執行會導致原子性問題,指令重排序會導致有序性問題,可見性(volatile的記憶體屏障可以解決可見性問題),原子性,有序性(指的是在程式執行的過程中程式碼的執行順序和我們的編寫順序是不一致的,這是由於編譯器的執行重排序,處理器的指令重排序,記憶體系統的重排序引起的,因為多個執行緒訪問記憶體的時候,他們之間是沒有順序的,要做到有序就要加鎖)都是我們抽象出來的概念,所以在JVM中引入了JMM的概念,這也是個抽象出來的概念。

JMM——Java記憶體模型

匯流排鎖,快取鎖是CPU層面的解決辦法,JMM是CPU和硬體層面(基於物理層面的抽象模型)抽象的一種記憶體模型。 Java記憶體模型定義了系統中共享記憶體在多執行緒程式讀寫操作時的規範,用來遮蔽各種硬體和作業系統的記憶體訪問的差異性,跟JVM有點類似,JVM是為了遮蔽作業系統的差異,提供了在作業系統層次上的虛擬機器可以真正實現一次編譯到處執行的效果。JMM最終是實現Java程式在各個平臺上都能達到一致性的記憶體保證效果。Java記憶體模型主要定義了程式中各個變數的訪問規則,也就是在虛擬機器中將變數儲存到記憶體以及從記憶體中取出變數這些操作的底層細節。通過這些規則來規範對記憶體的讀寫操作,保證指令執行的正確性。 Java記憶體模型與處理器,快取,併發,編譯器都有關,解決了CPU的多級快取,處理器優化,指令重排序等導致的記憶體訪問問題。 注:變數指的是共享變數,即例項物件,靜態欄位,陣列物件等儲存在堆記憶體中的變數,不包括區域性變數,因為他是執行緒私有的,不屬於共享變數。 JMM解決併發問題的方式:

一:限制處理器的優化 二:使用記憶體屏障 JMM定義了執行緒和記憶體的互動方式,在JMM抽象模型中,分為主記憶體(所有執行緒共享的)和工作記憶體(每個執行緒獨有的,相當於棧記憶體)。 主記憶體對映堆記憶體,硬體記憶體,而工作記憶體對映快取記憶體和暫存器。 執行緒對變數的讀寫操作必須在工作記憶體中進行,不能直接讀寫主記憶體的變數,不同的執行緒之間無法訪問對方的工作記憶體中的變數,執行緒之間的變數值的傳遞都需要通過主記憶體來完成。 執行緒在訪問記憶體的時候,JMM定義了8種原子操作來執行相應的操作,如Lock,鎖定了主記憶體的變數,保證執行緒的獨佔狀態: 這裡寫圖片描述 所以,在作業系統層面上存在的問題在JMM中也存在,只是在Java層面上把它抽象出來以後提供了相應的解決方案。JMM這種規範解決的就是由於多執行緒通過共享記憶體進行通訊時(執行緒之間的通訊方式:共享記憶體和訊息傳遞(notify,wait)),存在的本地記憶體資料不一致,編譯器會對程式碼指令重排序,處理器會對程式碼亂序執行帶來的問題,最終目的是保證併發場景中的原子性,可見性,有序性,而這個問題也是JMM模型本身存在的問題。