Java內存模型規定了在多線程程序中,什麼樣的行爲是容許出現的,什麼樣的行爲是禁止出現的。這樣說可能有點抽象,咱們換一個角度。將程序行爲抽象成讀操做和寫操做,每一個線程有本身的局部變量,同時線程之間還存在共享變量。那麼一個多線程程序執行結束後,全部變量會有一個最終值。Java內存模型來決定什麼樣的值合法,什麼樣的值不合法。html
內存模型不能要求的太嚴格,這樣會阻礙不少優化方法,下降程序執行的效率,但也不能要求的太鬆,由於這樣會致使一些執行結果違反咱們的直覺。例如指令間的重排序問題,若是線程內部的指令徹底按照程序中指明的次序執行,而且每次執行一條指令,執行的結果當即生效,那麼就會阻礙不少優化方法,但這樣對程序員是有好處的,由於程序員很容易推斷程序的執行結果,這樣寫出的程序就容易與本身的意圖一致。這種內存模型被稱爲順序一致性模型(Sequential Consistency)。反之,若是爲了優化程序執行效率,重排序的可能性有不少,那麼程序的效率是提升了,但對程序員來講,就很難推斷程序的執行結果。這一類的內存模型被稱爲Relaxed Memory Model。java
這樣,咱們就遇到了一個兩難的問題:git
而程序的效率,與程序是否容易寫對都很重要。爲了解決這個問題,科學家提出了 Data Race Free 的概念,它是對多線程程序同步程度的一種描述,基本的思想是若是多線程程序進行了正確的同步,那麼程序員就能夠按照順序一致性模型去推斷程序的執行結果,而底層對內存操做的實現,能夠按照 Relaxed Memory Model進行優化。程序員
Java 內存模型包含了兩方面的內容github
其中第一方面是與 Data Race Free相關的,第二方面與後面介紹的 Causality Requirements 相關。安全
Java 內存模型其實定義了好幾個概念來講明什麼是正確的同步。markdown
若是存在多個線程,同時訪問同一地址,而且至少有一個是寫操做,那麼這個程序存在衝突訪問多線程
兩個操做之間若是知足下面任意一個條件,就能夠說這兩個操做之間存在 happen-before order:併發
其中有些我也不是很理解。。oracle
全部存在衝突訪問的操做之間都有 happen-before order,那麼此多線程程序知足 data race free
假如多線程程序在順序一致性模型下執行,若是它知足 data race free,那麼此程序進行了正確的同步。
正確同步的多線程程序,其執行結果與在順序一致性模型下的執行結果一致。仔細體會下概念之間的關係。有點繞。
另外一方面,若是程序沒有正確同步,執行結果也不是任意的,必須對其進行限制,但限制又不能太強,由於太強會阻礙優化。因此 Java 內存模型使用了 Causality Requirements 的概念。
爲了精肯定義內存模型,Java語言規範中,提出了 Causality Requirements 的概念。不知道是什麼緣由,這個概念不多被說起,可是我以爲它是很重要的,但同時,也是很是使人費解的。語言規範中,首先定義了 Well-Formed Executions 的概念,如今對內存模型的不少討論,都是在這一層,它包括了對多線程程序執行中,與鎖,volatile變量,執行次序等等相關的規定。若是一個多線程程序的執行知足這些規定,那麼這個執行就是 Well-Formed Executions 的。國內有一個系列文章《深刻理解Java內存模型》,主要是在這方面描述Java內存模型。此外,在 Java 併發領域內著名的 Doug Lea 也給出了一個 The JSR-133 Cookbook for Compiler Writers,爲編譯器做者們提供參考,探討的也是這方面的問題。可是,內存模型對多線程程序的執行是否合法,不只僅要看它是不是 Well-Formed Executions,此次執行還須要知足 Causality Requirements。
語言規範中規定了一個構造過程,若是經過這個構造過程,能夠構造出多線程程序最終的執行結果,那麼此次執行就知足 Causality Requirements。構造過程從一個空集合C0開始,每次將其中添加若干操做,若是全部操做都能被添加,那麼構形成功。即,
C0 -> C1 -> C2 -> ... -> C
其中 C_i 是 C_(i+1) 的子集。你可能注意到了,以前說的「操做能被添加」,什麼叫操做能被添加呢?語言規範中規定了,每個 Ci 都對應一個 Ei,全部 Ei 都要知足 Well-Formed Executions。也就是說,若是你添加了操做後,對應的 Ei 不知足 Well-Formed Executions,那麼這個操做就不能被添加。若是最終,你的多線程程序沒法構造出這樣一個執行鏈,那麼,它的執行結果是非法的。
另外,Java 內存模型最初論文做者維護了一個頁面 The Java Memory Model,其中有一個條目叫 Causality Test Cases,給出了一些小例子,以便人們明白哪些行爲是知足 Causality Requirements 的,哪些是不知足的。此外,在 Java 併發領域內著名的 Doug Lea 也給出了一個 The JSR-133 Cookbook for Compiler Writers,爲編譯器做者們提供參考。不過聽說這份規範有些地方要求太嚴格了,開發者們仍是根據Java語言規範和虛擬機規範來開發。
參考資料:Java 語言規範以內存模型