JVM 虛擬機(3)JMM Java內(nèi)存模型

在學(xué)習Java內(nèi)存模型之前牙瓢,有幾個知識點必須先了解一下。
1. cpu和物理內(nèi)存的讀寫速度差會導(dǎo)致什么問題辜妓?如何解決?
2. 計算機內(nèi)存模型是什么忌怎?為什么需要計算機內(nèi)存模型籍滴?
最后再了解:
3. 什么是JMM?

cpu和物理內(nèi)存的讀寫速度差會導(dǎo)致什么問題榴啸?如何解決?

計算機的每條指令孽惰,都是通過cpu來執(zhí)行的,執(zhí)行過程中鸥印,大多情況下都需要與內(nèi)存打交道勋功。在早些時候,cpu的運算速度和內(nèi)存的運算速度相差無幾库说,于是兩者過的相安無事狂鞋。但是隨著cpu的不斷發(fā)展,cpu的計算速度遠遠超過了內(nèi)存璃弄。所以就導(dǎo)致每次cpu都要在等待內(nèi)存上耗費很長時間要销。
于是就誕生了高速緩存這一中間人构回,其實也就是我們平常所說的緩存夏块。它的作用時:在cpu進行計算時疏咐,先將所需的數(shù)據(jù)從內(nèi)存拷貝一份到高速緩存中,cpu在獲取數(shù)據(jù)時脐供,就直接從緩存中獲取浑塞,寫數(shù)據(jù)的時候,也可以直接往高速緩存中寫入政己。運算結(jié)束時酌壕,再將緩存中的數(shù)據(jù)刷新到內(nèi)存中即可。
舉個例子歇由,有一份工作需要張三和李四配合進行卵牍,張三負責工作前半部分,李四負責工作后半部分沦泌,起初兩者都是新手糊昙,干活速度不相上下,于是這個工作剛好能銜接上谢谦。但是隨著時間的積累释牺,李四的干活速度越來越快(cpu在升級),而張三的干活速度依舊如此(內(nèi)存的速度在原地踏步)回挽,所以導(dǎo)致李四干完了没咙,需要浪費很多時間在等待張三上。 所以呢千劈,公司為了這個問題祭刚,又招了王五作為協(xié)調(diào)員,又招了n個張三來做底層工作墙牌。協(xié)調(diào)員這邊負責將n個張三完成的工作緩存起來(高速緩存的作用)袁梗,等到李四開始工作時,直接與協(xié)調(diào)員對接即可憔古。

計算機內(nèi)存模型是什么遮怜?為什么需要計算機內(nèi)存模型?

咱們這先提一下計算機緩存鸿市,計算機緩存分一級緩存(L1 cache)锯梁、二級緩存(L2 cache)、三級緩存(L3 cache)焰情。當然不是所有計算機都配有這三級陌凳,也是看配置的。
在cpu執(zhí)行時内舟,會先從一級緩存中獲取數(shù)據(jù)合敦,如果沒有再從二級緩存中獲取數(shù)據(jù),如果還是沒有验游,則會去三級緩存或者內(nèi)存中獲取數(shù)據(jù)充岛。
對于多核cpu來說保檐,每個核都會有自己的一級緩存,二級緩存可能是共享的崔梗,也可能是單獨的夜只,而三級緩存一般來說都是共享的。


計算機三級緩存

說完了計算機緩存蒜魄,咱們再聊一下計算機的單線程和多線程扔亥,單核與多核的問題,這將對計算機內(nèi)存模型產(chǎn)生至關(guān)重要的影響谈为。
我們可以分下面幾種情況來考慮:

  1. 單線程(無論單核還是多核)
    單線程執(zhí)行旅挤,就不用考慮資源競爭的問題了,反正數(shù)據(jù)都是按順序讀的伞鲫,按順序?qū)懙那澹粫嬖诓l(fā)修改等并發(fā)問題,這種時候也就不需要對內(nèi)存數(shù)據(jù)進行什么保護措施榔昔,數(shù)據(jù)是絕對不可能亂的驹闰。

  2. 單核多線程
    單核是可以開啟多線程操作的,但不要誤以為這是并行撒会,你肉眼看著多個任務(wù)同時進行嘹朗,其實底層操作系統(tǒng)還是按著串行但方式在運行,操作系統(tǒng)是以時間片為單位控制著每個線程的掛起和執(zhí)行诵肛。
    舉例來說屹培,比如當下有a、b怔檩、c三個線程褪秀,操作系統(tǒng)給a分了10個時間片,于是a執(zhí)行了10個時間片后薛训,就被操作系統(tǒng)掛起了媒吗,緊接著又給b分了10個時間片,b執(zhí)行完后也被掛起了乙埃,如此反復(fù)闸英,因為一個時間片大概10ms左右,所以以人肉眼的角度來觀察多個任務(wù)的執(zhí)行情況介袜,其實是看不出這其實是在串行執(zhí)行甫何。
    所以,這也解釋了遇伞,這種情況下辙喂,其實也不需要對內(nèi)存數(shù)據(jù)做什么保障,串行已經(jīng)解決了一切臟數(shù)據(jù)問題。

  3. 多核多線程
    上面也說到了巍耗,每個核心秋麸,是有自己對一級緩存的,所以當core1上當線程1修改了該內(nèi)核下當L1緩存后芍锦,core2上當線程2修改了該內(nèi)核下當L1緩存,這時兩者當緩存數(shù)據(jù)就對不上了飞盆,如果這時候需要對這份數(shù)據(jù)進行其它計算娄琉,那就會導(dǎo)致計算錯誤。這其實也就是我們經(jīng)常說的緩存一致性問題吓歇。

除了上述多核多線程的情況會導(dǎo)致緩存不一致問題之外孽水,如果考慮硬件方面的話,還有其它情況城看,我這里就說一點:

  1. 指令重排序
    重排序是指編譯器和處理器為了優(yōu)化程序性能而對指令序列進行重新排序的一種手段女气。
    假設(shè)現(xiàn)在有如下兩句代碼要執(zhí)行:
    a = 1; a = 2;
    很明顯,先執(zhí)行a=1a=2测柠,對于a的結(jié)果值來說是顯然不同的兩種情況炼鞠。當然,在單線程情況下轰胁,操作系統(tǒng)會在遵守原有的串行邏輯的語義下谒主,對指令進行重排序,人話來說就是:我不會讓你對結(jié)果變的赃阀!
    但不同處理器和不同線程之間的數(shù)據(jù)性不會被編譯器和處理器考慮到霎肯,所以會因此而產(chǎn)生數(shù)據(jù)不一致的情況。

更詳細的文檔可參考:https://www.zybuluo.com/kiraSally/note/850631#24-%E9%87%8D%E6%8E%92%E5%BA%8F%E7%9A%84%E6%89%A7%E8%A1%8C%E6%B5%81%E7%A8%8B

那這些問題操作系統(tǒng)怎么解決呢榛斯?內(nèi)存模型观游!
簡單的來說,計算機內(nèi)存模型定義了兩種解決方式:

  1. 內(nèi)存屏障
  2. 限制處理器做優(yōu)化

什么是JMM驮俗?

  • Java內(nèi)存模型是一個抽象的概念懂缕,并非真實存在。
  • JMM定義了線程和主內(nèi)存之間的關(guān)系:
    1. 線程之間的共享變量存儲在主內(nèi)存中王凑。
    2. 每個線程都有一個私有的本地內(nèi)存提佣,其中保存了該線程使用到的共享變量的主內(nèi)存副本拷貝。
  • JMM屏蔽了操作系統(tǒng)和硬件的內(nèi)存訪問差異荤崇,所以Java才得意在各個平臺上達到訪問內(nèi)存的一致性拌屏。
  • 重點:主內(nèi)存和線程私有的工作內(nèi)存,與JVM的堆棧不是一回事术荤。主內(nèi)存應(yīng)該是指內(nèi)存條倚喂,而工作內(nèi)存應(yīng)該是指寄存器和高速緩存。

JMM的核心原則

多線程的原子性、可見性端圈、有序性焦读。
JMM是一種規(guī)范,目的是解決由于多線程通過共享內(nèi)存進行通信時舱权,存在的本地內(nèi)存數(shù)據(jù)不一致矗晃、編譯器會對代碼指令重排序、處理器會對代碼亂序執(zhí)行等帶來的問題宴倍。目的是保證并發(fā)編程場景中的原子性张症、可見性和有序性。

原子性

  • 原子性是指一個操作是不可中斷的鸵贬,即多線程環(huán)境下俗他,操作不能被其他線程干擾

可見性

  • 可見性是指當一個線程修改了某一個共享變量的值,其他線程是否能夠立即知道該變更
  • Java中普通的共享變量不保證可見性阔逼,因為其修改被寫入內(nèi)存的時機是不確定的兆衅,多線程并發(fā)下很可能出現(xiàn)"臟讀"
  • 緩存優(yōu)化或者硬件優(yōu)化或指令重排以及編輯器的優(yōu)化都可能導(dǎo)致一個線程修改不會立即被其他線程察覺
  • Java提供volatile保證可見性:寫操作立即刷新到主內(nèi)存,讀操作直接從主內(nèi)存讀取
  • Java同時還可以通過加鎖的同步性間接保證可見性:synchronized和Lock能保證同一時刻只有一個線程獲取鎖并執(zhí)行同步代碼嗜浮,并在釋放鎖之后將變量的修改刷新到主內(nèi)存中

有序性

  • 對于一個線程的執(zhí)行代碼而言羡亩,我們總是習慣性認為代碼的執(zhí)行總是從上到下,有序執(zhí)行危融,但為了提供性能夕春,編譯器和處理器通常會對指令序列進行重新排序
  • 指令重排可以保證串行語義一致,但沒有義務(wù)保證多線程間的語義也一致专挪,即可能產(chǎn)生"臟讀"

參考文章:
https://mp.weixin.qq.com/s/n0U2IJwhT3OAp_EwRdzYIA
https://www.zybuluo.com/kiraSally/note/850631#3happends-before

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末及志,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子寨腔,更是在濱河造成了極大的恐慌速侈,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件迫卢,死亡現(xiàn)場離奇詭異倚搬,居然都是意外死亡,警方通過查閱死者的電腦和手機乾蛤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門每界,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人家卖,你說我怎么就攤上這事眨层。” “怎么了上荡?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵趴樱,是天一觀的道長。 經(jīng)常有香客問我,道長叁征,這世上最難降的妖魔是什么纳账? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮捺疼,結(jié)果婚禮上疏虫,老公的妹妹穿的比我還像新娘。我一直安慰自己啤呼,他們只是感情好卧秘,可當我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著媳友,像睡著了一般斯议。 火紅的嫁衣襯著肌膚如雪产捞。 梳的紋絲不亂的頭發(fā)上醇锚,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天,我揣著相機與錄音坯临,去河邊找鬼焊唬。 笑死,一個胖子當著我的面吹牛看靠,可吹牛的內(nèi)容都是我干的赶促。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼挟炬,長吁一口氣:“原來是場噩夢啊……” “哼鸥滨!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起谤祖,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤婿滓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后粥喜,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凸主,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年额湘,在試婚紗的時候發(fā)現(xiàn)自己被綠了卿吐。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡锋华,死狀恐怖嗡官,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情毯焕,我是刑警寧澤谨湘,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響紧阔,放射性物質(zhì)發(fā)生泄漏坊罢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一擅耽、第九天 我趴在偏房一處隱蔽的房頂上張望活孩。 院中可真熱鬧,春花似錦乖仇、人聲如沸憾儒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽起趾。三九已至,卻和暖如春警儒,著一層夾襖步出監(jiān)牢的瞬間训裆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工蜀铲, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留边琉,地道東北人。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓记劝,卻偏偏與公主長得像变姨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子厌丑,可洞房花燭夜當晚...
    茶點故事閱讀 45,507評論 2 359

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