前面幾篇中,咱們談論了synchronized、final以及voilate的用法和底層實現,都繞不開一個話題-Java內存模型(java memory model,簡稱JMM)。Java內存模型是保證線程安全的基礎,主要描述了程序中全序的同步動做在不一樣線程訪問共享全局變量時所體現的原子性、可見性和有序性上的限制。java
一、定義編程
維基百科定義:The Java memory model describes how threads in the Java programming language interact through memory. Together with the description of single-threaded execution of code, the memory model provides the semantics of the Java programming language數組
大意是說:Java內存模型描述了多個Java線程如何與內存交互,同單線程執行同樣,在多線程場景下內存模型提供了一個合理正確Java編程語意。緩存
JSR133規範由JSR133專家組開發,並首次在Java5.0中實現。規範詳細準確的描述了多線程和內存交互語意,成爲Java規範的一部分,改進原有Java語意中錯誤,模凌兩可的部分,保證Java跨平臺性。安全
JSR133中關於內存模型的定義以下:多線程
給定一個程序和該程序的一串執行軌跡,內存模型描述了該執行軌跡是不是該程序 的一次合法執行。對於Java,內存模型檢查執行軌跡中的每次讀操做,而後根據特定規則,檢驗該讀操做觀察到的寫是否合法。內存模型描述了某個程序的可能行爲。JVM實現能夠自由地生成想要的代碼,只 要該程序全部最終執行產生的結果能經過內存模型進行預測。這爲大量的代碼轉換 提供了充分的自由,包括動做(action)的重排序以及非必要的同步移除。併發
內存模型的一個高級、非正式的概述顯示其是一組規則,規定了一個線程的寫操做什麼時候會對另外一個線程可見。通俗地說,讀操做r一般能看到任何寫操做w寫入的值,意味着w不是在r以後發生,且w看起來沒有被另外一個寫操做w'覆蓋掉(從 r 的角度看)。app
在本內存模型規範中使用「讀取(read)」這個詞時,僅是指讀取字段或數組元素的動做(action)。其它操做的語義,如讀取數組的長度,執行受檢轉換以及虛方法 調用,都不會被數據爭用直接影響到。JVM 實現有責任確保數據爭用不會致使諸如返回錯誤的數組長度或調用虛方法致使段錯誤這類不正確的行爲。ide
內存語義決定着程序中每一個時刻能讀到的值。每一個單個線程中的動做(action)必須表現爲被該線程的語義所控制,不包括讀操做看到的值由內存模型決定的狀況。當指的是這種情景時,咱們說該程序遵照線程內(intra-thread)語義。優化
二、JMM近似模型
爲了方便理解JMM,相比正式模型精確公式化的定義,JSR133提出了一種近似的模型-Happen-Before內存模型,這個描述是正式定義的必要非充分條件。首先須要解釋一下同步動做的定義,同步動做指的是鎖的加鎖解鎖,voilate對象讀取,線程動做以及探測線程是否結束等。與同步動做對應的是同步邊緣(synchronize-with邊緣),同步邊緣能夠理解爲同步動做間不可交疊屏障,包括如下幾點:
下面咱們詳細說一下這幾條限制,第一條說明了管程(synchronized底層實現monitor)的加鎖解鎖具備同步關係,包括兩點,同一個線程能夠對已加鎖對管程重複加鎖,保證解鎖次數同樣便可,對於已經被加鎖管程,線程阻塞並掛起。第二條volatile變量的寫操做會在以後其餘線程對volatile變量的讀操做有即時的體現,通常經過內存一致性協議實現,通常寫操做後會將對象的緩存寫入內存,並使得其餘核的緩存失效,從而讀取內存中最新修改的值,這兩條的實如今前面的文章中已有較詳細的說明。第三條和第四條都是描述線程的啓動在線程的第一個動做以前,線程最後一個動做在線程(探詢終止???這個不是很理解)終止以前,不得重排序。第五條描述的是線程A對線程B的中斷操做同步與線程B的中斷檢測動做,兩個動做互斥發生。第六條第七條說明了,變量的默認值在線程中第一個動做或者其餘操做以前,其實有時候編譯器會優化變量默認值但賦值,只要該變量還未使用。第八條說明了對象的字段在構造器中的初始化賦值和對象引用返回,final字段保證初始化賦值在對象引用返回以前,而非final字段不保證。
全部的同步動做構成的全局順序,稱之爲同步順序,而synchronize-with邊緣與程序順序構成了Happen-before順序,也就是Happen-before內存模型。Java內存模型是Happen-before內存模型的子集,由於Happen-before模型不少時候違背了因果關係,最爲致命的弱點是「值的憑空出現」。關於Java內存模型的正式規範請參考JSR133第7章內容(我也看的雲裏霧裏--!)
三、總結
總的來講,內存模型這個概念是由Java語言首先提出,在保證java語義完整性健壯性上起到了很大做用,C/C++以及其餘語言在鎖多線程併發模型上也參考這樣的內存模型。理解JMM能讓咱們更加深入的正確理解JAVA多線程併發執行中與內存交互的邏輯,從而編寫出健壯高效的併發程序。