掌握好這些Java內(nèi)存模型知識(shí),你才算一個(gè)合格的程序員看尼!

小編的話

在文章的開始作者為大家整理了很多資料递鹉!包括一線大廠Java面試題總結(jié)+各知識(shí)點(diǎn)學(xué)習(xí)思維導(dǎo)+一份300頁pdf文檔的Java核心知識(shí)點(diǎn)總結(jié)! 這些資料的內(nèi)容都是面試時(shí)面試官必問的知識(shí)點(diǎn)藏斩,篇章包括了很多知識(shí)點(diǎn)躏结,其中包括了有基礎(chǔ)知識(shí)、Java集合狰域、JVM媳拴、多線程并發(fā)、spring原理兆览、微服務(wù)屈溉、Netty 與RPC 、Kafka抬探、日記子巾、設(shè)計(jì)模式、Java算法小压、數(shù)據(jù)庫砰左、Zookeeper、分布式緩存场航、數(shù)據(jù)結(jié)構(gòu)等等缠导。


你要是需要的話點(diǎn)這里直接下載就好了,希望對(duì)你有幫助

Java內(nèi)存模型

簡單介紹一下Java內(nèi)存模型

Java內(nèi)存模型即Java Memory Model溉痢,簡稱JMM僻造。JMM定義了Java 虛擬機(jī)(JVM)在計(jì)算機(jī)內(nèi)存(RAM)中的工作方式。JVM是整個(gè)計(jì)算機(jī)虛擬模型孩饼,所以JMM是隸屬于JVM的髓削。

Java內(nèi)存模型是共享內(nèi)存的并發(fā)模型,線程之間主要通過讀-寫共享變量(堆內(nèi)存中的實(shí)例域镀娶,靜態(tài)域和數(shù)組元素)來完成隱式通信立膛。Java 內(nèi)存模型(JMM)控制 Java 線程之間的通信,決定一個(gè)線程對(duì)共享變量的寫入何時(shí)對(duì)另一個(gè)線程可見。

JVM主內(nèi)存與工作內(nèi)存

Java 內(nèi)存模型的主要目標(biāo)是定義程序中各個(gè)變量的訪問規(guī)則宝泵,即在虛擬機(jī)中將變量(線程共享的變量)存儲(chǔ)到內(nèi)存和從內(nèi)存中取出變量這樣底層細(xì)節(jié)好啰。

Java內(nèi)存模型中規(guī)定了所有的變量都存儲(chǔ)在主內(nèi)存中,每條線程還有自己的工作內(nèi)存儿奶,線程對(duì)變量的所有操作都必須在工作內(nèi)存中進(jìn)行同衣,而不能直接讀寫主內(nèi)存中的變量古今。這里的工作內(nèi)存是 JMM 的一個(gè)抽象概念,也叫本地內(nèi)存,其存儲(chǔ)了該線程以讀 / 寫共享變量的副本夺衍。

就像每個(gè)處理器內(nèi)核擁有私有的高速緩存芥被,JMM 中每個(gè)線程擁有私有的本地內(nèi)存诽里。不同線程之間無法直接訪問對(duì)方工作內(nèi)存中的變量手负,線程間的通信一般有兩種方式進(jìn)行,一是通過消息傳遞茬祷,二是共享內(nèi)存沐飘。Java 線程間的通信采用的是共享內(nèi)存方式,線程牲迫、主內(nèi)存和工作內(nèi)存的交互關(guān)系如下圖所示:


線程A和線程B通信要經(jīng)過兩個(gè)步驟:

線程A把本地內(nèi)存A中更新過的共享變量刷新到主內(nèi)存中
線程B到主內(nèi)存中去讀取線程A之前已更新過的共享變量
這里所講的主內(nèi)存耐朴、工作內(nèi)存與 Java 內(nèi)存區(qū)域中的 Java 堆、棧盹憎、方法區(qū)等并不是同一個(gè)層次的內(nèi)存劃分筛峭,這兩者基本上是沒有關(guān)系的,如果兩者一定要勉強(qiáng)對(duì)應(yīng)起來陪每,那從變量影晓、主內(nèi)存、工作內(nèi)存的定義來看檩禾,主內(nèi)存主要對(duì)應(yīng)于Java堆中的對(duì)象實(shí)例數(shù)據(jù)部分挂签,而工作內(nèi)存則對(duì)應(yīng)于虛擬機(jī)棧中的部分區(qū)域。

JMM數(shù)據(jù)原子操作

read(讀扰尾):從主內(nèi)存讀取數(shù)據(jù)
load(載入):將主內(nèi)存讀取到的數(shù)據(jù)寫入工作內(nèi)存
use(使用):從工作內(nèi)存讀取數(shù)據(jù)來計(jì)算
assign(賦值):將計(jì)算好的值重新賦值到工作內(nèi)存中
store(存儲(chǔ)):將工作內(nèi)存數(shù)據(jù)寫入主內(nèi)存
write(寫入):將store過去的變量值賦值給主內(nèi)存中的變量
lock(鎖定):將主內(nèi)存變量加鎖饵婆,標(biāo)識(shí)為線程獨(dú)占狀態(tài)
unlock(解鎖):將主內(nèi)存變量解鎖,解鎖后其他線程可以鎖定該變量

public class VolatileVisibilityTest {

    private static volatile boolean initFlag = false;

    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("waiting data...");
                while (!initFlag) {
                }
                System.out.println("====================success");
            }
        }).start();

        Thread.sleep(2000);

        new Thread(new Runnable() {
            @Override
            public void run() {
                prepareDate();
            }
        }).start();
    }

    public static void prepareDate() {
        System.out.println("preparing data...");
        initFlag = true;
        System.out.println("prepare end...");
    }
}


計(jì)算機(jī)高速緩存和緩存一致性

計(jì)算機(jī)在高速的 CPU 和相對(duì)低速的存儲(chǔ)設(shè)備之間使用高速緩存戏售,作為內(nèi)存和處理器之間的緩沖侨核。將運(yùn)算需要使用到的數(shù)據(jù)復(fù)制到緩存中,讓運(yùn)算能快速運(yùn)行灌灾,當(dāng)運(yùn)算結(jié)束后再從緩存同步回內(nèi)存之中搓译。

在多處理器的系統(tǒng)中(或者單處理器多核的系統(tǒng)),每個(gè)處理器內(nèi)核都有自己的高速緩存锋喜,它們有共享同一主內(nèi)存(Main Memory)些己。當(dāng)多個(gè)處理器的運(yùn)算任務(wù)都涉及同一塊主內(nèi)存區(qū)域時(shí),將可能導(dǎo)致各自的緩存數(shù)據(jù)不一致。

為此段标,需要各個(gè)處理器訪問緩存時(shí)都遵循一些協(xié)議涯冠,在讀寫時(shí)要根據(jù)協(xié)議進(jìn)行操作,來維護(hù)緩存的一致性怀樟。

MESI緩存一致性協(xié)議:多個(gè)CPU從主存讀取同一個(gè)數(shù)據(jù)到各自的告訴緩存,當(dāng)其中某個(gè)CPU修改了緩存里的數(shù)據(jù)盆佣,該數(shù)據(jù)會(huì)馬上同步會(huì)主內(nèi)存往堡,其他CPU通過總線嗅探機(jī)制可以感知到數(shù)據(jù)的變化從而將自己緩存里的數(shù)據(jù)失效。



volatile緩存可見性實(shí)現(xiàn)原理

底層實(shí)現(xiàn)主要通過匯編lock前綴指令共耍,它會(huì)鎖定這塊內(nèi)存區(qū)域的緩存(緩存行鎖定)并回寫到主存

1)會(huì)將當(dāng)前處理器緩存行的數(shù)據(jù)立即寫回到系統(tǒng)內(nèi)存
2)這個(gè)寫回內(nèi)存的操作會(huì)引起在其他CPU里緩存了該內(nèi)存地址的數(shù)據(jù)無效(MESI)

重排序和happens-before規(guī)則

在執(zhí)行程序時(shí)為了提高性能虑灰,編譯器和處理器常常會(huì)對(duì)指令做重排序。重排序分三種類型:

編譯器優(yōu)化的重排序痹兜。編譯器在不改變單線程程序語義的前提下穆咐,可以重新安排語句的執(zhí)行順序。
指令級(jí)并行的重排序∽中瘢現(xiàn)代處理器采用了指令級(jí)并行技術(shù)(Instruction-Level Parallelism对湃, ILP)來將多條指令重疊執(zhí)行。如果不存在數(shù)據(jù)依賴性遗淳,處理器可以改變語句對(duì)應(yīng)機(jī)器指令的執(zhí)行順序拍柒。
內(nèi)存系統(tǒng)的重排序。由于處理器使用緩存和讀 / 寫緩沖區(qū)屈暗,這使得加載和存儲(chǔ)操作看上去可能是在亂序執(zhí)行拆讯。
從 java 源代碼到最終實(shí)際執(zhí)行的指令序列,會(huì)分別經(jīng)歷下面三種重排序:

JMM 屬于語言級(jí)的內(nèi)存模型养叛,它確保在不同的編譯器和不同的處理器平臺(tái)之上种呐,通過禁止特定類型的編譯器重排序和處理器重排序,為程序員提供一致的內(nèi)存可見性保證弃甥。java 編譯器禁止處理器重排序是通過在生成指令序列的適當(dāng)位置會(huì)插入內(nèi)存屏障(重排序時(shí)不能把后面的指令重排序到內(nèi)存屏障之前的位置)指令來實(shí)現(xiàn)的爽室。

happens-before

從 JDK5 開始,java 內(nèi)存模型提出了 happens-before 的概念淆攻,通過這個(gè)概念來闡述操作之間的內(nèi)存可見性肮之。如果一個(gè)操作執(zhí)行的結(jié)果需要對(duì)另一個(gè)操作可見,那么這兩個(gè)操作之間必須存在 happens-before 關(guān)系卜录。這里提到的兩個(gè)操作既可以是在一個(gè)線程之內(nèi)戈擒,也可以是在不同線程之間。這里的“可見性”是指當(dāng)一條線程修改了這個(gè)變量的值艰毒,新值對(duì)于其他線程來說是可以立即得知的筐高。

如果 A happens-before B,那么 Java 內(nèi)存模型將向程序員保證—— A 操作的結(jié)果將對(duì) B 可見,且 A 的執(zhí)行順序排在 B 之前柑土。

重要的 happens-before 規(guī)則如下:

程序順序規(guī)則:一個(gè)線程中的每個(gè)操作蜀肘,happens- before 于該線程中的任意后續(xù)操作。
監(jiān)視器鎖規(guī)則:對(duì)一個(gè)監(jiān)視器鎖的解鎖稽屏,happens- before 于隨后對(duì)這個(gè)監(jiān)視器鎖的加鎖扮宠。
volatile 變量規(guī)則:對(duì)一個(gè) volatile 域的寫,happens- before 于任意后續(xù)對(duì)這個(gè) volatile 域的讀狐榔。
傳遞性:如果 A happens- before B坛增,且 B happens- before C,那么 A happens- before C薄腻。
下圖是 happens-before 與 JMM 的關(guān)系

最后

在文章的最后作者為大家整理了很多資料收捣!包括一線大廠Java面試題總結(jié)+各知識(shí)點(diǎn)學(xué)習(xí)思維導(dǎo)+一份300頁pdf文檔的Java核心知識(shí)點(diǎn)總結(jié)! 這些資料的內(nèi)容都是面試時(shí)面試官必問的知識(shí)點(diǎn)庵楷,篇章包括了很多知識(shí)點(diǎn)罢艾,其中包括了有基礎(chǔ)知識(shí)、Java集合尽纽、JVM咐蚯、多線程并發(fā)、spring原理弄贿、微服務(wù)仓蛆、Netty 與RPC 、Kafka挎春、日記看疙、設(shè)計(jì)模式、Java算法直奋、數(shù)據(jù)庫能庆、Zookeeper、分布式緩存脚线、數(shù)據(jù)結(jié)構(gòu)等等搁胆。
歡迎關(guān)注公眾號(hào):前程有光,領(lǐng)扔事獭渠旁!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市船逮,隨后出現(xiàn)的幾起案子顾腊,更是在濱河造成了極大的恐慌,老刑警劉巖挖胃,帶你破解...
    沈念sama閱讀 221,406評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件杂靶,死亡現(xiàn)場離奇詭異梆惯,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)吗垮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門垛吗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人烁登,你說我怎么就攤上這事怯屉。” “怎么了饵沧?”我有些...
    開封第一講書人閱讀 167,815評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵锨络,是天一觀的道長。 經(jīng)常有香客問我捷泞,道長足删,這世上最難降的妖魔是什么寿谴? 我笑而不...
    開封第一講書人閱讀 59,537評(píng)論 1 296
  • 正文 為了忘掉前任锁右,我火速辦了婚禮,結(jié)果婚禮上讶泰,老公的妹妹穿的比我還像新娘咏瑟。我一直安慰自己,他們只是感情好痪署,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,536評(píng)論 6 397
  • 文/花漫 我一把揭開白布码泞。 她就那樣靜靜地躺著,像睡著了一般狼犯。 火紅的嫁衣襯著肌膚如雪余寥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,184評(píng)論 1 308
  • 那天悯森,我揣著相機(jī)與錄音宋舷,去河邊找鬼。 笑死瓢姻,一個(gè)胖子當(dāng)著我的面吹牛祝蝠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播幻碱,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼绎狭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了褥傍?” 一聲冷哼從身側(cè)響起儡嘶,我...
    開封第一講書人閱讀 39,668評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎恍风,沒想到半個(gè)月后社付,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體承疲,經(jīng)...
    沈念sama閱讀 46,212評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,299評(píng)論 3 340
  • 正文 我和宋清朗相戀三年鸥咖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了燕鸽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,438評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡啼辣,死狀恐怖啊研,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鸥拧,我是刑警寧澤党远,帶...
    沈念sama閱讀 36,128評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站富弦,受9級(jí)特大地震影響沟娱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜腕柜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,807評(píng)論 3 333
  • 文/蒙蒙 一济似、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧盏缤,春花似錦砰蠢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至潭流,卻和暖如春竞惋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背灰嫉。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評(píng)論 1 272
  • 我被黑心中介騙來泰國打工拆宛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人熬甫。 一個(gè)月前我還...
    沈念sama閱讀 48,827評(píng)論 3 376
  • 正文 我出身青樓胰挑,卻偏偏與公主長得像,于是被迫代替她去往敵國和親椿肩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瞻颂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,446評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容