面試高頻問題:JAVA的鎖升級

背景

在java中佳遣,經(jīng)常會用到synchronized關(guān)鍵字來保證線程安全崎岂,那么什么時候會存在線程安全呢慎陵?

  • 共享數(shù)據(jù)的修改
  • 臨界資源訪問

應(yīng)用場景

  • 修飾普通同步方法:鎖當(dāng)前實例對象讥蟆;
  • 修飾靜態(tài)同步方法:鎖當(dāng)前的類Class對象拒垃;
  • 修飾同步代碼塊:鎖Synchronized后面括號里配置的對象窍侧,這個對象可以是任意對象县踢;

synchronized原理

在絕大多數(shù)情況下,都只會有一個線程去訪問synchronized修飾的代碼塊伟件,所以synchronized在jdk1.6之后為了提升效率硼啤,優(yōu)化了synchronized的機制,就是所謂的鎖升級斧账。通過對象頭ObjectMonitor對象將鎖劃分了幾個類型谴返,其升級順序為:無鎖->偏向鎖->輕量級鎖->重量級鎖煞肾,要了解它的原理,則必須要了解對象頭嗓袱。

對象頭

java對象保存在內(nèi)存中籍救,由3個部分組成:

  • 對象頭

  • 實例數(shù)據(jù)

  • 對齊填充字節(jié)

    這里,我們只對對象頭加以說明

1渠抹、對象頭的存在形式

JVM中的對象頭有兩種形式蝙昙,它由三部分組成:

  • Mark Word
  • Klass Pointer(指向類的指針)
  • 數(shù)組長度(只有數(shù)組對象才有)
1.1 普通對象
|--------------------------------------------------------------|
|                     Object Header (64 bits)                  |
|------------------------------------|-------------------------|
|        Mark Word (32 bits)         |    Klass Word (32 bits) |
|------------------------------------|-------------------------|
1.2 數(shù)組對象
|---------------------------------------------------------------------------------|
|                                 Object Header (96 bits)                         |
|--------------------------------|-----------------------|------------------------|
|        Mark Word(32bits)       |    Klass Word(32bits) |  array length(32bits)  |
|--------------------------------|-----------------------|------------------------|
2、對象頭組成
2.1 MarkWord

這部分主要存儲對象自身的運行時數(shù)據(jù)梧却,如hashCode,gc分代年齡奇颠,鎖標記等等。MarkWord的長度根據(jù)jvm來確認放航,32位的JVM的mark word為32bit烈拒,64位的mark word為64bit。當(dāng)一個對象被synchronized關(guān)鍵字當(dāng)成同步鎖時广鳍,圍繞這個鎖的一系列操作都和Mark Word有關(guān)荆几。

Mark Word在不同的鎖狀態(tài)下,存儲不同赊时,在32位JVM中是這樣的:

|-------------------------------------------------------|-----------------------------------------|
|                  Mark Word (32 bits)                 |       狀態(tài)                                |
|----------------------------------------- -------------|-----------------------------------------|
| identity hashcode:25 | 分代年齡:4 | 是否偏向鎖:1 | 鎖標志位:2 |無鎖        |
|------------------------------------------------------|----------------------------------------  |
|  thread id:23 | epoch:2 | 分代年齡:4 | 是否偏向鎖:1 | 鎖標志位:2 |  偏向鎖|
|-----------------------------------------------------|--------------------|
|               指向棧中鎖記錄的指針:30          | 鎖標志位:2   |           輕量級鎖|
|--------------------------------------  -------------|-------------------------------------------|
|               指向重量級鎖的指針:30  | 鎖標志位:2 |                    重量級鎖  |
|----------------------------------------------------|-------------------------------------------|
|                 空                     | 鎖標志位:2 |GC  標記

注意:hashCode與identity hashcode并非完全是一個東西伴郁,identity hashcode是Object的hashCode

2.2 指向類的指針

該指針在32位JVM中的長度是32bit,在64位JVM中長度是64bit蛋叼。

Java對象的類數(shù)據(jù)保存在方法區(qū)焊傅。

2.3 數(shù)組長度

只有數(shù)組對象保存了這部分數(shù)據(jù)。

該數(shù)據(jù)在32位和64位JVM中長度都是32bit狈涮。

Monitor

當(dāng)鎖膨脹為重量級鎖時狐胎,多個線程來訪問一段同步代碼時,這些線程會被放到一個EntrySet集合中歌馍,處于阻塞狀態(tài)的線程都會被放到該列表中握巢。接下來,當(dāng)線程獲取到對象的Monitor時松却,Monitor是依賴于底層操作系統(tǒng)的mutex lock來實現(xiàn)互斥的暴浦,線程獲取mutex成功,則會持有改mutex晓锻,這時其他線程就無法再獲取到該mutex

如果線程調(diào)用了wait方法歌焦,那么該線程就會釋放掉所持有的mutex,并且該線程會進入到WaitSet集合中,等待下一次被其他線程調(diào)用notify/notifyAll喚醒砚哆。如果當(dāng)前線程順利執(zhí)行完畢方法独撇,那么它也會釋放掉所持有的mutex。

由于這種實現(xiàn)方式纷铣,Monitor是依賴底層的操作系統(tǒng)實現(xiàn),這樣存在用戶態(tài)和內(nèi)核態(tài)之間的切換以躯,所以會增加性能開銷啄踊。

鎖升級的過程

JVM一般是這樣使用鎖和Mark Word的:

1忧设、當(dāng)沒有被當(dāng)做鎖的時候社痛,這就是個普通對象命雀,鎖標志位為01,是否偏向鎖為0

2撵儿、當(dāng)對象被當(dāng)做同步鎖時狐血,一個線程A搶到鎖時,鎖標志位依然是01匈织,是否偏向鎖為1,前23位記錄A線程的線程ID纳决,此時鎖升級為偏向鎖

3乡小、當(dāng)線程A再次試圖來獲得鎖時,JVM發(fā)現(xiàn)同步鎖對象的標志位是01满钟,是否偏向鎖是1,也就是偏向狀態(tài)湃番,Mark Word中記錄的線程id就是線程A自己的id,表示線程A已經(jīng)獲得了這個偏向鎖摔癣,可以執(zhí)行同步鎖的代碼,這也是偏向鎖的意義

4择浊、當(dāng)一個線程B嘗試獲取鎖,JVM發(fā)現(xiàn)當(dāng)前的鎖處于偏向狀態(tài)投剥,并且現(xiàn)場ID不是B線程的ID担孔,那么線程B會先用CAS將線程id改為自己的,這里是有可能成功的糕篇,因為A線程一般不會釋放偏向鎖。如果失敗挑豌,則執(zhí)行5

5墩崩、偏向鎖搶鎖失敗氓英,則說明當(dāng)前鎖存在一定的競爭鹦筹,偏向鎖就升級為輕量級鎖。JVM會在當(dāng)前線程的現(xiàn)場棧中開辟一塊單獨的空間徘键,里面保存指向?qū)ο箧iMark Word的指針遍蟋,同時在對象鎖MarkWord中保存指向這片空間的指針。上面的保存都是CAS操作匿值,如果競爭成功,代表線程B搶到了鎖钟些,可以執(zhí)行同步代碼绊谭。如果搶鎖失敗,則繼續(xù)執(zhí)行6

6达传、輕量級鎖搶鎖失敗迫筑,則JVM會使用自旋鎖宗弯,自旋鎖并非是一個鎖,則是一個循環(huán)操作辕棚,不斷的嘗試獲取鎖邓厕。從JDK1.7開始,自旋鎖默認開啟详恼,自旋次數(shù)由JVM決定。如果搶鎖成功挽铁,則執(zhí)行同步代碼硅堆;如果搶鎖失敗贿讹,則執(zhí)行7

7、自旋鎖重試之后仍然未搶到鎖民褂,同步鎖會升級至重量級鎖,鎖標志位改為10面殖,在這個狀態(tài)下哭廉,未搶到鎖的線程都會被阻塞,由Monitor來管理遵绰,并會有線程的park與unpark,因為這個存在用戶態(tài)和內(nèi)核態(tài)的轉(zhuǎn)換乌企,比較消耗資源成玫,故名重量級鎖

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市猪腕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌渗柿,老刑警劉巖脖岛,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異陨溅,居然都是意外死亡绍在,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門臼寄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來溜宽,“玉大人,你說我怎么就攤上這事留攒〖掂郑” “怎么了?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵拭宁,是天一觀的道長瓣俯。 經(jīng)常有香客問我,道長降铸,這世上最難降的妖魔是什么推掸? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任驻仅,我火速辦了婚禮登渣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘粘优。我一直安慰自己呻顽,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著喉前,像睡著了一般。 火紅的嫁衣襯著肌膚如雪裕便。 梳的紋絲不亂的頭發(fā)上见咒,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天论颅,我揣著相機與錄音囱嫩,去河邊找鬼恃疯。 笑死墨闲,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的盾鳞。 我是一名探鬼主播瞻离,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼套利,長吁一口氣:“原來是場噩夢啊……” “哼鹤耍!你這毒婦竟也來了验辞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤杆怕,失蹤者是張志新(化名)和其女友劉穎壳贪,沒想到半個月后违施,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡伟姐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年愤兵,在試婚紗的時候發(fā)現(xiàn)自己被綠了排吴。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秆乳。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡钻哩,死狀恐怖屹堰,靈堂內(nèi)的尸體忽然破棺而出街氢,到底是詐尸還是另有隱情扯键,我是刑警寧澤荣刑,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布厉亏,位于F島的核電站烈和,受9級特大地震影響招刹,放射性物質(zhì)發(fā)生泄漏沥匈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望散址。 院中可真熱鬧宣赔,春花似錦儒将、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至踊东,卻和暖如春刚操,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背坚冀。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工遗菠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人豁遭。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓捂蕴,卻偏偏與公主長得像,于是被迫代替她去往敵國和親啥辨。 傳聞我的和親對象是個殘疾皇子溉知,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,901評論 2 355