Java內(nèi)存模型與硬件內(nèi)存架構(gòu)的關(guān)系
多線程的指向最終都映射在硬件處理器上進(jìn)行執(zhí)行画髓,但是Java內(nèi)存模型與硬件內(nèi)存架構(gòu)并不完全一致徘郭,對(duì)于硬件內(nèi)存來說之后寄存器端朵、緩存內(nèi)存液肌、主內(nèi)存概念之分,并沒有工作內(nèi)存焰络、主內(nèi)存之分戴甩,也就是說Java內(nèi)存模型對(duì)內(nèi)存的劃分對(duì)硬件內(nèi)存并沒有任何影響,因?yàn)镴MM只是一種抽象的概念闪彼,是一種規(guī)則甜孤,并不實(shí)際存在,這個(gè)規(guī)范存在的意義是定義了程序各個(gè)變量的訪問方式畏腕,屏蔽掉各種硬件和操作系統(tǒng)的內(nèi)存訪問差異缴川,以實(shí)現(xiàn)讓java程序在各種平臺(tái)下都能達(dá)到一致的并發(fā)效果。不管是工作內(nèi)存還是主內(nèi)存的數(shù)據(jù)描馅,對(duì)于計(jì)算機(jī)硬件來說都會(huì)存儲(chǔ)在計(jì)算機(jī)主內(nèi)存中把夸,當(dāng)然有可能存儲(chǔ)袋CPU緩存或者寄存器中,因此Java內(nèi)存模型和計(jì)算機(jī)硬件內(nèi)存架構(gòu)是一種相互交叉的關(guān)系铭污,是一種抽象概念劃分與真實(shí)物理硬件的交叉
重排序
as-if-serial語義
不管怎么重排序恋日,程序的執(zhí)行結(jié)果不能被改變,編譯器嘹狞、runtime和處理器都必須遵守as-if-serial語義岂膳。編譯器和處理器不會(huì)對(duì)存在數(shù)據(jù)依賴關(guān)系的操作做重排序,因?yàn)檫@種重排序會(huì)改變執(zhí)行結(jié)果磅网,但是闷营,如果操作之間不存在數(shù)據(jù)依賴關(guān)系,這些操作就可能被編譯器和處理器做重排序知市。
重排序種類
- 編譯器優(yōu)化的重排序;
- 指令級(jí)并行的重排序速蕊;
- 內(nèi)存系統(tǒng)的重排序嫂丙;
如何禁止重排序
對(duì)于編譯器,JMM編譯器重排序規(guī)則會(huì)禁止特定類型的編譯器重排序规哲;
對(duì)于處理器跟啤,JMM的處理器重排序規(guī)則會(huì)要求Java編譯器在生成指令序列時(shí),插入特定類型的內(nèi)存屏障指令,通過內(nèi)存屏障指令來禁止特定類型的處理器重排序隅肥。
內(nèi)存屏障
為什么會(huì)有內(nèi)存屏障竿奏?
- 每個(gè)CPU都會(huì)有自己的緩存(有的甚至有三級(jí)緩存),緩存的目的就是為了提高性能腥放,避免每次都要向內(nèi)存取泛啸,但是這樣的弊端也是很明顯:不能實(shí)時(shí)和內(nèi)存發(fā)生信息交換,分在不同CPU執(zhí)行的不同線程對(duì)同一變量的緩存值不同秃症。
- 用Volatile關(guān)鍵字修飾變量可以解決上述問題候址,Volatile通過內(nèi)存屏障來實(shí)現(xiàn),內(nèi)存屏障是硬件層的概念种柑,不同的硬件平臺(tái)實(shí)現(xiàn)內(nèi)存屏障的手段并不是一樣的岗仑,java通過屏蔽這些差異,統(tǒng)一由jvm來生成內(nèi)存屏障指令聚请。
作用
- 確保指令重排序時(shí)不會(huì)把屏障后面的指令排到內(nèi)存屏障之前的位置荠雕,也不會(huì)把前面的指令排到內(nèi)存屏障后面。
- 強(qiáng)制把寫緩沖區(qū)/高速緩存中的數(shù)據(jù)等寫回主內(nèi)存驶赏,讓緩存中相應(yīng)的數(shù)據(jù)失效炸卑;
Load Barrier 讀屏障
在指令前插入Load Barrier,可以讓高速緩存中的數(shù)據(jù)失效母市,強(qiáng)制重新從主內(nèi)存加載數(shù)據(jù)矾兜;
Store Barrier 寫屏障
利用緩存一致性機(jī)制強(qiáng)制將對(duì)緩存的修改操作立即寫入主存,讓其他線程可見患久,并且緩存一致性機(jī)制會(huì)阻止同時(shí)修改由兩個(gè)以上CPU緩存的內(nèi)存區(qū)域數(shù)據(jù)椅寺。
內(nèi)存屏障類型
為了保證可見性,Java編譯器在生成指令序列的適當(dāng)位置會(huì)插入內(nèi)存屏障指令來禁止特定類型的處理器重排序蒋失。
其中StoreLoad指令是現(xiàn)代多處理器都需要使用的返帕,但是它的開銷也很昂貴。
volatile插入屏障策略
- 在每個(gè)volatile寫操作的前面插入一個(gè)StoreStore屏障篙挽;
- 在每個(gè)volatile寫操作的后面插入StoreLoad屏障荆萤;
- 在每個(gè)volatile讀操作的后面插入LoadLoad屏障;
- 在每個(gè)volatile讀操作的后面插入LoadStore屏障铣卡;
實(shí)現(xiàn)原理
Volatile變量 寫匯編指令會(huì)多出#Lock前綴链韭,Lock前綴在多核處理器下的作用:
- 將當(dāng)前處理器緩存行的數(shù)據(jù)寫會(huì)主存啄踊;
- 令其他CPU里緩存該內(nèi)存地址的數(shù)據(jù)失效倔喂;(總線鎖定雾家?MESI緩存一致性協(xié)議)