併發編程的3個源頭問題分別是:html
Java內存模型就是爲了解決可見性和有序性問題。java
緩存會致使可見性問題,編譯優化會致使有序性問題。若是要避免這兩個問題,最簡單的方法不就是禁用緩存和編譯優化。這樣就丟掉了優化程序性能的有利武器,顯然是不可取的。程序員
合理的方案應該是按需禁用緩存以及編譯優化。什麼叫按需禁用緩存以及編譯優化呢?指的就是程序員在寫代碼的過程當中,對有可能出現併發問題的代碼禁用緩存和編譯優化。編程
Java內存模型就是禁用緩存和編譯優化的一種規範,它規範了 JVM 如何提供按需禁用緩存和編譯優化的方法。如今提到的 Java 內存模型,通常指的是 JDK 5 開始使用內存模型,遵循的是 JSR-133 描述的規範。緩存
JSR133Java內存模型是一個雄心勃勃的計劃,它是編程語言規範第一次嘗試合併一個可以在各類處理器架構中爲併發提供一致語義的內存模型。不過,定義一個既一致又直觀的內存模型遠比想象要更難。JSR133 爲Java語言定義了一個新的內存模型,它修復了早期內存模型中的缺陷。爲了實現 JSR133,final和volatile的語義須要從新定義。架構
完整的語義見:http://www.cs.umd.edu/users/p...,可是正式的語義不是當心翼翼的,它是使人驚訝和清醒的,目的是讓人意識到一些看似簡單的概念(如同步)其實有多複雜。幸運的是,你不須要懂得這些正式語義的細節——JSR133的目的是建立一組正式語義,這些正式語義提供了volatile、synchronzied和final如何工做的直觀框架。併發
—— Java內存模型FAQ(三)JSR133是什麼?app
Java內存模型主要分紅兩部分,一部分面向併發編程的開發人員,一部分面向JVM開發人員,咱們須要關注的是前者。前者主要包括 volatile
、synchronized
和 final
三個關鍵字,以及六項 Happens-Before
規則。框架
Java內存模型是按需禁用緩存和編譯優化的規則。Happens-Before 表示前面一個操做對後面一個操做是可見的,它約束了編譯器的優化行爲,編譯器能夠優化,可是須要遵循 Happens-Before 規則。編程語言
有這樣 6 條和可見性相關的規範:
前面提到過,如今所說的 Java 內存模型通常指的是 Java1.5 以後的內存模型,它遵循 JSR-133 描述的規範。採用新的規範的緣由是舊的 Java 內存模型存在問題,好比:對 final 修飾的變量進行過分的編譯優化,以及 volatile 的語義問題。
// 如下代碼來源於【參考1】 class VolatileExample { int x = 0; volatile boolean v = false; public void writer() { x = 42; v = true; } public void reader() { if (v == true) { // 這裏x會是多少呢? } } }
上面這段代碼,變量 v 是一個 volatile 類型的變量,則會禁用緩存,全部線程對 v 的操做都是直接從內存中讀取。此時,線程 A 執行 writer() 方法,則 v = true 會被寫入內存;同時線程 B 執行 reader() 方法,顯然會經過 if 判斷,那麼此時 x 的值會是多少?
在 Java1.5 以前,x 的值多是 0,也有多是 42。由於 x 有可能被 CPU 緩存起來,致使可見性問題。這顯然不是咱們指望的狀況,因此在新的 Java 內存模型中對 volatile 的語音進行了加強,就是依靠 Happens-Before 中的 volatile 變量規則和傳遞性規則。
如上圖所示,線程 A 執行 writer() 方法,線程 B 執行 reader() 方法:
此時,經過 Happens-Before 規則對 volatile 變量的語義加強,線程 B 讀到的 x 就必定是 42,而不會存在是 0 的狀況,符合咱們對程序的期待。
JSR 133 (Java Memory Model) FAQ