1、JMM基礎-計算機原理
Java內存模型即Java Memory Model,簡稱JMM。JMM定義了Java 虛擬機(JVM)在計算機內存(RAM)中的工作方式。JVM是整個計算機虛擬模型,所以JMM是隸屬于JVM的。Java1.5版本對其進行了重構,現在的Java仍沿用了Java1.5的版本。Jmm遇到的問題與現代計算機中遇到的問題是差不多的。
物理計算機中的并發(fā)問題,物理機遇到的并發(fā)問題與虛擬機中的情況有不少相似之處,物理機對并發(fā)的處理方案對于虛擬機的實現也有相當大的參考意義。
根據《Jeff Dean在Google全體工程大會的報告》我們可以看到
計算機在做一些我們平時的基本操作時,需要的響應時間是不一樣的。
(以下案例僅做說明,并不代表真實情況。)
如果從內存中讀取1M的int型數據由CPU進行累加,耗時要多久?
做個簡單的計算,1M的數據,Java里int型為32位,4個字節(jié),共有1024*1024/4 = 262144個整數 ,則CPU 計算耗時:262144 *0.6 = 157 286 納秒,而我們知道從內存讀取1M數據需要250000納秒,兩者雖然有差距(當然這個差距并不小,十萬納秒的時間足夠CPU執(zhí)行將近二十萬條指令了),但是還在一個數量級上。但是,沒有任何緩存機制的情況下,意味著每個數都需要從內存中讀取,這樣加上CPU讀取一次內存需要100納秒,262144個整數從內存讀取到CPU加上計算時間一共需要262144*100+250000 = 26 464 400 納秒,這就存在著數量級上的差異了。
而且現實情況中絕大多數的運算任務都不可能只靠處理器“計算”就能完成,處理器至少要與內存交互,如讀取運算數據、存儲運算結果等,這個I/O操作是基本上是無法消除的(無法僅靠寄存器來完成所有運算任務)。早期計算機中cpu和內存的速度是差不多的,但在現代計算機中,cpu的指令速度遠超內存的存取速度,由于計算機的存儲設備與處理器的運算速度有幾個數量級的差距,所以現代計算機系統都不得不加入一層讀寫速度盡可能接近處理器運算速度的高速緩存(Cache)來作為內存與處理器之間的緩沖:將運算需要使用到的數據復制到緩存中,讓運算能快速進行,當運算結束后再從緩存同步回內存之中,這樣處理器就無須等待緩慢的內存讀寫了。
在計算機系統中,寄存器劃是L0級緩存,接著依次是L1,L2,L3(接下來是內存,本地磁盤,遠程存儲)。越往上的緩存存儲空間越小,速度越快,成本也更高;越往下的存儲空間越大,速度更慢,成本也更低。從上至下,每一層都可以看做是更下一層的緩存,即:L0寄存器是L1一級緩存的緩存,L1是L2的緩存,依次類推;每一層的數據都是來至它的下一層,所以每一層的數據是下一層的數據的子集。
在現代CPU上,一般來說L0, L1,L2,L3都集成在CPU內部,而L1還分為一級數據緩存(Data Cache,D-Cache,L1d)和一級指令緩存(Instruction Cache,I-Cache,L1i),分別用于存放數據和執(zhí)行數據的指令解碼。每個核心擁有獨立的運算處理單元、控制器、寄存器、L1、L2緩存,然后一個CPU的多個核心共享最后一層CPU緩存L3。
2、Java內存模型(JMM)
從抽象的角度來看,JMM定義了線程和主內存之間的抽象關系:線程之間的共享變量存儲在主內存(Main Memory)中,每個線程都有一個私有的本地內存(Local Memory),本地內存中存儲了該線程以讀/寫共享變量的副本。本地內存是JMM的一個抽象概念,并不真實存在。它涵蓋了緩存、寫緩沖區(qū)、寄存器以及其他的硬件和編譯器優(yōu)化。