Java 內(nèi)存模型 JMM 基礎(chǔ)及原子性、可見性向图、有序性

問:簡(jiǎn)單談?wù)勀銓?duì) Java 虛擬機(jī)內(nèi)存模型 JMM 的認(rèn)識(shí)和理解及并發(fā)中的原子性泳秀、可見性、有序性的理解榄攀?

答:Java 內(nèi)存模型主要目標(biāo)是定義程序中變量(此處變量特指實(shí)例字段嗜傅、靜態(tài)字段等,但不包括局部變量和函數(shù)參數(shù)檩赢,因?yàn)檫@兩種是線程私有無(wú)法共享)吕嘀。在虛擬機(jī)中存儲(chǔ)到內(nèi)存與從內(nèi)存讀取出來(lái)的規(guī)則細(xì)節(jié),Java 內(nèi)存模型規(guī)定所有變量都存儲(chǔ)在主內(nèi)存中贞瞒,每條線程還有自己的工作內(nèi)存偶房,工作內(nèi)存保存了該線程使用到的變量到主內(nèi)存副本拷貝,線程對(duì)變量的所有操作(讀取军浆、賦值)都必須在工作內(nèi)存中進(jìn)行而不能直接讀寫主內(nèi)存中的變量棕洋,不同線程之間無(wú)法相互直接訪問對(duì)方工作內(nèi)存中的變量,線程間變量值的傳遞均需要在主內(nèi)存來(lái)完成(具體如下圖)乒融。

Java 內(nèi)存模型對(duì)主內(nèi)存與工作內(nèi)存之間的具體交互協(xié)議定義了八種操作掰盘,具體如下:
  • lock(鎖定):作用于主內(nèi)存變量摄悯,把一個(gè)變量標(biāo)識(shí)為一條線程獨(dú)占狀態(tài)。

  • unlock(解鎖):作用于主內(nèi)存變量愧捕,把一個(gè)處于鎖定狀態(tài)的變量釋放出來(lái)奢驯,釋放后的變量才可以被其他線程鎖定。

  • read(讀然尾啤):作用于主內(nèi)存變量叨橱,把一個(gè)變量從主內(nèi)存?zhèn)鬏數(shù)骄€程的工作內(nèi)存中,以便隨后的 load 動(dòng)作使用断盛。

  • load(載入):作用于工作內(nèi)存變量,把 read 操作從主內(nèi)存中得到的變量值放入工作內(nèi)存的變量副本中愉舔。

  • use(使用):作用于工作內(nèi)存變量钢猛,把工作內(nèi)存中的一個(gè)變量值傳遞給執(zhí)行引擎,每當(dāng)虛擬機(jī)遇到一個(gè)需要使用變量值的字節(jié)碼指令時(shí)執(zhí)行此操作轩缤。

  • assign(賦值):作用于工作內(nèi)存變量命迈,把一個(gè)從執(zhí)行引擎接收的值賦值給工作內(nèi)存的變量,每當(dāng)虛擬機(jī)遇到一個(gè)需要給變量進(jìn)行賦值的字節(jié)碼指令時(shí)執(zhí)行此操作火的。

  • store(存儲(chǔ)):作用于工作內(nèi)存變量壶愤,把工作內(nèi)存中一個(gè)變量的值傳遞到主內(nèi)存中,以便后續(xù) write 操作馏鹤。

  • write(寫入):作用于主內(nèi)存變量征椒,把 store 操作從工作內(nèi)存中得到的值放入主內(nèi)存變量中。

如果要把一個(gè)變量從主內(nèi)存復(fù)制到工作內(nèi)存就必須按順序執(zhí)行 read 和 load 操作湃累,從工作內(nèi)存同步回主內(nèi)存就必須順序執(zhí)行 store 和 write 操作勃救,但是 JVM 只要求了操作的順序而沒有要求上述操作必須保證連續(xù)性,所以實(shí)質(zhì)執(zhí)行中 read 和 load 間及 store 和 write 間是可以插入其他指令的治力。

Java 內(nèi)存模型還會(huì)對(duì)指令進(jìn)行重排序操作蒙秒,在執(zhí)行程序時(shí)為了提高性能編譯器和處理器經(jīng)常會(huì)對(duì)指令進(jìn)行重排序操作,重排序主要分下面幾類:

  • 編譯器優(yōu)化重排序:編譯器在不改變單線程程序語(yǔ)義的前提下可以重新安排語(yǔ)句的執(zhí)行順序宵统。

  • 指令級(jí)并行重排序:現(xiàn)代處理器采用了指令級(jí)并行技術(shù)來(lái)將多條指令重疊執(zhí)行晕讲,如果不存在數(shù)據(jù)依賴性處理器可以改變語(yǔ)句對(duì)應(yīng)機(jī)器指令的執(zhí)行順序。

  • 內(nèi)存系統(tǒng)重排序:由于處理器使用緩存和讀寫緩沖區(qū)使得加載和存儲(chǔ)操作看上去可能是在亂序執(zhí)行马澈。

其實(shí) Java JMM 內(nèi)存模型是圍繞并發(fā)編程中原子性瓢省、可見性、有序性三個(gè)特征來(lái)建立的箭券,關(guān)于原子性净捅、可見性、有序性的理解如下:
  • 原子性:就是說一個(gè)操作不能被打斷辩块,要么執(zhí)行完要么不執(zhí)行蛔六,類似事務(wù)操作荆永,Java 基本類型數(shù)據(jù)的訪問大都是原子操作,long 和 double 類型是 64 位国章,在 32 位 JVM 中會(huì)將 64 位數(shù)據(jù)的讀寫操作分成兩次 32 位來(lái)處理具钥,所以 long 和 double 在 32 位 JVM 中是非原子操作,也就是說在并發(fā)訪問時(shí)是線程非安全的液兽,要想保證原子性就得對(duì)訪問該數(shù)據(jù)的地方進(jìn)行同步操作骂删,譬如 synchronized 等。

  • 可見性:就是說當(dāng)一個(gè)線程對(duì)共享變量做了修改后其他線程可以立即感知到該共享變量的改變四啰,從 Java 內(nèi)存模型我們就能看出來(lái)多線程訪問共享變量都要經(jīng)過線程工作內(nèi)存到主存的復(fù)制和主存到線程工作內(nèi)存的復(fù)制操作宁玫,所以普通共享變量就無(wú)法保證可見性了;Java 提供了 volatile 修飾符來(lái)保證變量的可見性柑晒,每次使用 volatile 變量都會(huì)主動(dòng)從主存中刷新欧瘪,除此之外 synchronized、Lock匙赞、final 都可以保證變量的可見性佛掖。

  • 有序性:就是說 Java 內(nèi)存模型中的指令重排不會(huì)影響單線程的執(zhí)行順序,但是會(huì)影響多線程并發(fā)執(zhí)行的正確性涌庭,所以在并發(fā)中我們必須要想辦法保證并發(fā)代碼的有序性芥被;在 Java 里可以通過 volatile 關(guān)鍵字保證一定的有序性,還可以通過 synchronized坐榆、Lock 來(lái)保證有序性拴魄,因?yàn)?synchronized、Lock 保證了每一時(shí)刻只有一個(gè)線程執(zhí)行同步代碼相當(dāng)于單線程執(zhí)行猛拴,所以自然不會(huì)有有序性的問題羹铅;除此之外 Java 內(nèi)存模型通過 happens-before 原則如果能推導(dǎo)出來(lái)兩個(gè)操作的執(zhí)行順序就能先天保證有序性,否則無(wú)法保證愉昆,關(guān)于 happens-before 原則可以查閱相關(guān)資料职员。

所以說如果想讓 Java 并發(fā)程序正確的執(zhí)行必須保證原子性、有序性跛溉、可見性焊切,只要三者中有任意一個(gè)不滿足并發(fā)都無(wú)法正確執(zhí)行。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末芳室,一起剝皮案震驚了整個(gè)濱河市专肪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌堪侯,老刑警劉巖嚎尤,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異伍宦,居然都是意外死亡芽死,警方通過查閱死者的電腦和手機(jī)乏梁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)关贵,“玉大人遇骑,你說我怎么就攤上這事∫驹” “怎么了落萎?”我有些...
    開封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵逮栅,是天一觀的道長(zhǎng)矾湃。 經(jīng)常有香客問我棒呛,道長(zhǎng)独柑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任空猜,我火速辦了婚禮则北,結(jié)果婚禮上邢隧,老公的妹妹穿的比我還像新娘粱坤。我一直安慰自己,他們只是感情好瓷产,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開白布站玄。 她就那樣靜靜地躺著,像睡著了一般濒旦。 火紅的嫁衣襯著肌膚如雪株旷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天尔邓,我揣著相機(jī)與錄音晾剖,去河邊找鬼。 笑死梯嗽,一個(gè)胖子當(dāng)著我的面吹牛齿尽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播灯节,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼循头,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了炎疆?” 一聲冷哼從身側(cè)響起卡骂,我...
    開封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎形入,沒想到半個(gè)月后全跨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡亿遂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年浓若,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了渺杉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡七嫌,死狀恐怖少办,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情诵原,我是刑警寧澤英妓,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站绍赛,受9級(jí)特大地震影響蔓纠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吗蚌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一腿倚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蚯妇,春花似錦敷燎、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至陨收,卻和暖如春饭豹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背务漩。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工拄衰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人饵骨。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓翘悉,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親宏悦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子镐确,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

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