Java內(nèi)存模型

JVM三部分:

1.類加載子系統(tǒng)
2.內(nèi)存空間(運行時數(shù)據(jù)空間)
3.執(zhí)行引擎

image.png

JVM運行時數(shù)據(jù)區(qū)

image.png

XXX.java ---->編譯后:XXX.class ---->類裝載子系統(tǒng)--->裝載至JVM運行時數(shù)據(jù)區(qū)(內(nèi)存)--->執(zhí)行引擎執(zhí)行
由所有線程共享的數(shù)據(jù)區(qū):方法區(qū)油猫,堆
線程隔離數(shù)據(jù)區(qū):java棧夕凝,本地方法棧铃绒,程序計數(shù)器

數(shù)據(jù)結(jié)構(gòu):https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

image.png

堆鸽照,垃圾回收GC方式 針對full GC(zgc,G1颠悬,cms)


image.png

內(nèi)存可見性矮燎、重排序、順序一致性、volatile腻扇、鎖障陶、final

Valatile 實現(xiàn)及應(yīng)用

volatile關(guān)鍵字,在轉(zhuǎn)為匯編語言后浅乔,會發(fā)現(xiàn)有l(wèi)ock前綴的指令

0x0000000002931351: lock add dword ptr [rsp],0h  ;*putstatic instance
                                                ; - org.xrq.test.design.singleton.LazySingleton::getInstance@13 (line 14)

lock前綴指令會強制處理器將修改內(nèi)容回寫到內(nèi)存,同時铝条,通過緩存一致性協(xié)議(MESI)來控制緩存一致
即靖苇,一個處理器的緩存回寫到內(nèi)存會導(dǎo)致其他處理器的緩存無效

MESI: modified(修改),exclusive(獨占)班缰,share(共享)贤壁,Invalid(無效)

具體步驟及結(jié)果參考:http://www.cnblogs.com/xrq730/p/7048693.html


synchronized 實現(xiàn)及原理

Java中每一個對象都可以作為鎖,這是synchronized實現(xiàn)同步的基礎(chǔ):
1. 普通同步方法埠忘,鎖是當(dāng)前實例對象
2. 靜態(tài)同步方法脾拆,鎖是當(dāng)前類的class對象
3. 同步方法塊,鎖是括號里面的對象

Java 虛擬機中的同步(Synchronization)基于進入和退出管程(Monitor)對象實現(xiàn)莹妒, 無論是顯式同步(有明確的 monitorenter 和 monitorexit 指令,即同步代碼塊)還是隱式同步都是如此名船。在 Java 語言中,同步用的最多的地方可能是被 synchronized 修飾的同步方法旨怠。同步方法 并不是由 monitorenter 和 monitorexit 指令來實現(xiàn)同步的渠驼,而是由方法調(diào)用指令讀取運行時常量池中方法的 ACC_SYNCHRONIZED 標(biāo)志來隱式實現(xiàn)的

如下

public class SynchronizedTest {
    public synchronized void test1(){

    }

    public void test2(){
        synchronized (this){

        }
    }
}

利用javap工具查看生成的class文件信息來分析Synchronize的實現(xiàn)


image.png

Java對象頭,這對深入理解synchronized實現(xiàn)原理非常關(guān)鍵鉴腻。

所有的Java對象是天生的Monitor迷扇,每一個Java對象都有成為Monitor的潛質(zhì),因為在Java的設(shè)計中 爽哎,每一個Java對象自打娘胎里出來就帶了一把看不見的鎖蜓席,它叫做內(nèi)部鎖或者Monitor鎖。

理解Java對象頭與Monitor

本段摘自:https://blog.csdn.net/javazejian/article/details/72828483

在JVM中课锌,對象在內(nèi)存中的布局分為三塊區(qū)域:對象頭厨内、實例數(shù)據(jù)和對齊填充。如下:

image.png
  • 實例變量:存放類的屬性數(shù)據(jù)信息,包括父類的屬性信息隘庄,如果是數(shù)組的實例部分還包括數(shù)組的長度踢步,這部分內(nèi)存按4字節(jié)對齊。

  • 填充數(shù)據(jù):由于虛擬機要求對象起始地址必須是8字節(jié)的整數(shù)倍丑掺。填充數(shù)據(jù)不是必須存在的获印,僅僅是為了字節(jié)對齊,這點了解即可街州。

而對于頂部兼丰,則是Java頭對象,它實現(xiàn)synchronized的鎖對象的基礎(chǔ)唆缴,這點我們重點分析它鳍征,一般而言,synchronized使用的鎖對象是存儲在Java對象頭里的面徽,jvm中采用2個字來存儲對象頭(如果對象是數(shù)組則會分配3個字艳丛,多出來的1個字記錄的是數(shù)組長度),其主要結(jié)構(gòu)是由Mark Word 和 Class Metadata Address 組成趟紊,其結(jié)構(gòu)說明如下表:

虛擬機位數(shù) 頭對象結(jié)構(gòu) 說明
32/64bit Mark Word 存儲對象的hashCode氮双、鎖信息或分代年齡或GC標(biāo)志等信息
32/64bit Class Metadata Address 類型指針指向?qū)ο蟮念愒獢?shù)據(jù),JVM通過這個指針確定該對象是哪個類的實例霎匈。

其中Mark Word在默認情況下存儲著對象的HashCode戴差、分代年齡、鎖標(biāo)記位等以下是32位JVM的Mark Word默認存儲結(jié)構(gòu)

鎖狀態(tài) 25bit 4bit 1bit是否是偏向鎖 2bit 鎖標(biāo)志位
無鎖狀態(tài) 對象HashCode 對象分代年齡 0 01

由于對象頭的信息是與對象自身定義的數(shù)據(jù)沒有關(guān)系的額外存儲成本铛嘱,因此考慮到JVM的空間效率暖释,Mark Word 被設(shè)計成為一個非固定的數(shù)據(jù)結(jié)構(gòu),以便存儲更多有效的數(shù)據(jù)墨吓,它會根據(jù)對象本身的狀態(tài)復(fù)用自己的存儲空間球匕,如32位JVM下,除了上述列出的Mark Word默認存儲結(jié)構(gòu)外帖烘,還有如下可能變化的結(jié)構(gòu):

其中輕量級鎖和偏向鎖是Java 6 對 synchronized 鎖進行優(yōu)化后新增加的谐丢,稍后我們會簡要分析。這里我們主要分析一下重量級鎖也就是通常說synchronized的對象鎖蚓让,鎖標(biāo)識位為10,其中指針指向的是monitor對象(也稱為管程或監(jiān)視器鎖)的起始地址讥珍。每個對象都存在著一個 monitor 與之關(guān)聯(lián)历极,對象與其 monitor 之間的關(guān)系有存在多種實現(xiàn)方式,如monitor可以與對象一起創(chuàng)建銷毀或當(dāng)線程試圖獲取對象鎖時自動生成衷佃,但當(dāng)一個 monitor 被某個線程持有后趟卸,它便處于鎖定狀態(tài)。在Java虛擬機(HotSpot)中,monitor是由ObjectMonitor實現(xiàn)的锄列,其主要數(shù)據(jù)結(jié)構(gòu)如下(位于HotSpot虛擬機源碼ObjectMonitor.hpp文件图云,C++實現(xiàn)的)

ObjectMonitor() {
    _header       = NULL;
    _count        = 0; //記錄個數(shù)
    _waiters      = 0,
    _recursions   = 0;
    _object       = NULL;
    _owner        = NULL;
    _WaitSet      = NULL; //處于wait狀態(tài)的線程,會被加入到_WaitSet
    _WaitSetLock  = 0 ;
    _Responsible  = NULL ;
    _succ         = NULL ;
    _cxq          = NULL ;
    FreeNext      = NULL ;
    _EntryList    = NULL ; //處于等待鎖block狀態(tài)的線程邻邮,會被加入到該列表
    _SpinFreq     = 0 ;
    _SpinClock    = 0 ;
    OwnerIsThread = 0 ;
  }

ObjectMonitor中有兩個隊列竣况,_WaitSet 和 _EntryList,用來保存ObjectWaiter對象列表( 每個等待鎖的線程都會被封裝成ObjectWaiter對象)筒严,_owner指向持有ObjectMonitor對象的線程丹泉,當(dāng)多個線程同時訪問一段同步代碼時,首先會進入 _EntryList 集合鸭蛙,當(dāng)線程獲取到對象的monitor 后進入 _Owner 區(qū)域并把monitor中的owner變量設(shè)置為當(dāng)前線程同時monitor中的計數(shù)器count加1摹恨,若線程調(diào)用 wait() 方法,將釋放當(dāng)前持有的monitor娶视,owner變量恢復(fù)為null晒哄,count自減1,同時該線程進入 WaitSe t集合中等待被喚醒肪获。若當(dāng)前線程執(zhí)行完畢也將釋放monitor(鎖)并復(fù)位變量的值寝凌,以便其他線程進入獲取monitor(鎖)。如下圖所示

image.png

由此看來贪磺,monitor對象存在于每個Java對象的對象頭中(存儲的指針的指向)硫兰,synchronized鎖便是通過這種方式獲取鎖的,也是為什么Java中任意對象可以作為鎖的原因

當(dāng)一個線程訪問同步代碼塊時寒锚,它首先是需要得到鎖才能執(zhí)行同步代碼劫映,當(dāng)退出或者拋出異常時必須要釋放鎖

Java虛擬機對synchronized的優(yōu)化
鎖的四種狀態(tài):

無鎖狀態(tài)
偏向鎖狀態(tài):只有一個線程進入臨界區(qū)(加鎖解鎖不需要額外消耗,直接比較對象頭里當(dāng)前持有的線程ID刹前,但是如果存在鎖競爭會有額外的所撤銷消耗)
輕量級鎖狀態(tài):多個線程先后(交替)進入臨界區(qū)(線程競爭使用自旋泳赋,不會阻塞,但是始終得不到鎖會消耗CPU)
重量級鎖狀態(tài):多個線程同時進入臨界區(qū)(線程競爭不使用自旋喇喉,不會消耗CPU祖今,但是線程阻塞,相應(yīng)時間緩慢)

鎖升級觸發(fā)條件:

處于偏向鎖狀態(tài)時拣技,有其他線程發(fā)起鎖競爭千诬,原持有鎖線程未退出同步代碼塊——>升級為輕量級鎖狀態(tài)
處于輕量級鎖狀態(tài)時,其他線程多次自旋膏斤,cas操作仍然失敗徐绑,未獲取到鎖——>升級為重量級鎖狀態(tài)
處于重量級鎖狀態(tài)時,線程會阻塞莫辨,等待原持有鎖線程完成后退出再被喚醒

image.png

參考:
https://www.zhihu.com/question/53826114
https://blog.csdn.net/javazejian/article/details/72828483

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末傲茄,一起剝皮案震驚了整個濱河市毅访,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌盘榨,老刑警劉巖喻粹,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異草巡,居然都是意外死亡守呜,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進店門捷犹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弛饭,“玉大人,你說我怎么就攤上這事萍歉÷滤蹋” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵枪孩,是天一觀的道長憔晒。 經(jīng)常有香客問我,道長蔑舞,這世上最難降的妖魔是什么拒担? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮攻询,結(jié)果婚禮上从撼,老公的妹妹穿的比我還像新娘。我一直安慰自己钧栖,他們只是感情好低零,可當(dāng)我...
    茶點故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著拯杠,像睡著了一般掏婶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上潭陪,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天雄妥,我揣著相機與錄音,去河邊找鬼依溯。 笑死老厌,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的黎炉。 我是一名探鬼主播梅桩,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼拜隧!你這毒婦竟也來了宿百?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤洪添,失蹤者是張志新(化名)和其女友劉穎垦页,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體干奢,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡痊焊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了忿峻。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片薄啥。...
    茶點故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖逛尚,靈堂內(nèi)的尸體忽然破棺而出垄惧,到底是詐尸還是另有隱情,我是刑警寧澤绰寞,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布到逊,位于F島的核電站,受9級特大地震影響滤钱,放射性物質(zhì)發(fā)生泄漏觉壶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一件缸、第九天 我趴在偏房一處隱蔽的房頂上張望铜靶。 院中可真熱鬧,春花似錦他炊、人聲如沸争剿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秒梅。三九已至,卻和暖如春舌胶,著一層夾襖步出監(jiān)牢的瞬間捆蜀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工幔嫂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留辆它,地道東北人。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓履恩,卻偏偏與公主長得像锰茉,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子切心,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,678評論 2 354

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