Synchronized的實(shí)現(xiàn)原理

最近在看《Java并發(fā)編程的藝術(shù)》伦籍,看到一個(gè)常見的面試點(diǎn) Synchronized實(shí)現(xiàn)原理嫩舟,這塊知識(shí)工作中也用不到声功,但是我們還是有必要了解下這個(gè)醒串,畢竟我們是專業(yè)的执桌。

本文主體思路
1.Monitor
2.實(shí)例對(duì)象的存儲(chǔ)構(gòu)成
3.偏向鎖、輕量鎖芜赌、重量鎖
4.鎖的膨脹過(guò)程
5.鎖的對(duì)比

1.Monitor

顧名思義仰挣,對(duì)象的監(jiān)視器,只要發(fā)生同步操作缠沈,線程就為當(dāng)前對(duì)象創(chuàng)建一個(gè)Monitor對(duì)象與之關(guān)聯(lián)膘壶,Monitor只能被一個(gè)線程持有,此時(shí)當(dāng)前對(duì)象就處于鎖定狀態(tài)洲愤,其它線程只能阻塞等待颓芭。

Java虛擬機(jī)(HotSpot)中,Monitor是通過(guò)ObjectMonitor實(shí)現(xiàn)的(c++)柬赐,里面有三個(gè)重要的屬性

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

Monitor 有兩個(gè)隊(duì)列 _WaitSet 和 _EntryList肛宋,存儲(chǔ)ObjectWaiter列表(所有等待的線程都會(huì)被包裝成ObjectWaiter)州藕;① 線程申請(qǐng)owner Monitor對(duì)象,首先會(huì)被加入到 _EntryList 酝陈;② 線程申請(qǐng)owner Monitor對(duì)象床玻,進(jìn)入到 Owner區(qū)域,此時(shí)_count +1沉帮; ③線程調(diào)用wait方法锈死,釋放鎖贫堰,進(jìn)入到 _WaitSet ,此時(shí)_count -1 ④ 線程再次申請(qǐng)owner ⑤ 線程處理完畢后釋放資源并退出待牵。

Synchronized 鎖的管理就是依托于Monitor严嗜,當(dāng)線程owner Monitor的時(shí)候則擁有進(jìn)行同步操作的權(quán)利,線程進(jìn)入同步塊調(diào)用monitorenter指令洲敢,退出同步塊則調(diào)用monitorexit漫玄,釋放對(duì)Monitor的持有。

如何獲取鎖也就是如何owner Monitor呢压彭?

2.實(shí)例對(duì)象構(gòu)成

實(shí)例對(duì)象結(jié)構(gòu)

對(duì)象頭
主要存放 MarkWord睦优,MarkWord里存儲(chǔ)了對(duì)象的hashcode 以及鎖信息等。除了MarkWord 對(duì)象頭里還存放類的元信息--Class對(duì)象的指針(內(nèi)存地址)壮不。如果數(shù)組的話汗盘,還會(huì)再存儲(chǔ)下數(shù)組的長(zhǎng)度。

實(shí)例數(shù)據(jù)
實(shí)例數(shù)據(jù)部分是對(duì)象真正存儲(chǔ)的有效信息询一,也是程序代碼中所定義的各種類型的字段內(nèi)容隐孽。包括從父類繼承來(lái)的,都會(huì)記錄下來(lái)健蕊。

對(duì)齊填充
HotSpot要求對(duì)象的起止地址(姑且認(rèn)為是對(duì)象大小)必須是8的整數(shù)倍菱阵,對(duì)象頭部分正好是8的倍數(shù),因此當(dāng)實(shí)例數(shù)據(jù)部分不是8的倍數(shù)的話就需要填充了缩功。

3.偏向鎖晴及、輕量鎖、重量鎖

JavaSE1.6為了減少獲得鎖和釋放鎖帶來(lái)的性能消耗嫡锌,引入了偏向鎖虑稼、輕量鎖。而鎖的信息則是在對(duì)象頭的MarkWord里势木。Mark Word的存儲(chǔ)內(nèi)容會(huì)隨著鎖的變化而變化蛛倦,下面的表格就是不同的鎖狀態(tài)對(duì)應(yīng)的存儲(chǔ)內(nèi)容。
MarkWord 不同鎖狀態(tài)對(duì)應(yīng)的存儲(chǔ)

鎖的變化歸根結(jié)底還是線程改寫Mark Word的操作啦桌。

3.1偏向鎖

HotSpot 作者經(jīng)過(guò)研究發(fā)現(xiàn)溯壶,大多數(shù)情況下,鎖不僅不存在競(jìng)爭(zhēng)而且總由同一個(gè)線程獲得震蒋,為了讓線程獲取鎖的代價(jià)更低茸塞,引入了偏向鎖。

偏向鎖的獲取
case1
當(dāng)前是無(wú)鎖狀態(tài)查剖,是則將自己的線程id钾虐,寫入到Mark Word,同時(shí)是否是偏向鎖寫入1笋庄,當(dāng)前線程持有該對(duì)象的偏向鎖
case2
當(dāng)前對(duì)象已經(jīng)是偏向鎖效扫,判斷Mark Word里存的 線程id是不是自己的倔监,如果是則繼續(xù)持有偏向鎖
case3
當(dāng)前對(duì)象已經(jīng)是偏向鎖,并且Mark Word里存的 線程id也不是自己的菌仁,當(dāng)前線程用過(guò)CAS嘗試將Mark Word里的線程id改寫成自己浩习,如果改寫成功則當(dāng)前線程持有偏向鎖

偏向鎖的撤銷
上面case3,如果當(dāng)前線程嘗試改寫Mark Word的線程ID為自己济丘,改寫失敗谱秽,等待進(jìn)入全局安全點(diǎn)的時(shí)候,它(個(gè)人覺得是JVM)首先暫停原持有偏向鎖的線程摹迷,然后檢查原持有偏向鎖的線程是否處于不活動(dòng)或者退出同步疟赊,是則當(dāng)前線程將自己線程id寫入Mark Word,持有偏向鎖峡碉。否則當(dāng)前線程將對(duì)象標(biāo)記為輕量級(jí)鎖近哟。原持有偏向鎖的線程恢復(fù)執(zhí)行,執(zhí)行完畢退出同步塊并喚醒暫停的線程鲫寄。

關(guān)閉偏向鎖配置
java6和7里默認(rèn)是開啟偏向鎖的吉执,如果你確定應(yīng)用程序里所有的鎖通常是處于競(jìng)爭(zhēng)狀態(tài),可以通過(guò)jvm參數(shù)配置關(guān)閉偏向鎖

XX:-UseBiasedLocking=false

3.2 輕量鎖

輕量級(jí)鎖加鎖
線程執(zhí)行同步塊之前地来,JVM會(huì)先在當(dāng)前線程的棧楨中穿件存儲(chǔ)鎖記錄的空間戳玫,并將對(duì)象頭的Mark Word 復(fù)制到鎖記錄,官方稱 Displaced Mark Word靠抑。然后線程嘗試將對(duì)象頭Mark Word替換為指向鎖記錄的指針也就是Displaced Mark Word的內(nèi)存地址量九,同時(shí)改寫鎖標(biāo)識(shí)為00适掰。如果替換成功則持有偏向鎖颂碧。如果失敗則嘗試自旋獲取,自旋有次數(shù)限制类浪,超過(guò)后則膨脹為重量級(jí)鎖载城。

輕量級(jí)鎖解鎖
輕量級(jí)解鎖,會(huì)通過(guò)CAS將Displaced Mark Word替換回到對(duì)象頭费就,如果成功則沒(méi)有競(jìng)爭(zhēng)诉瓦,退出同步塊。失敗則說(shuō)明存在競(jìng)爭(zhēng)力细,膨脹為重量級(jí)鎖睬澡。

3.3 重量鎖

這個(gè)則是最原始的鎖競(jìng)爭(zhēng)則阻塞,鎖釋放則喚醒

3.4 幾個(gè)鎖對(duì)應(yīng)的Mark Word的變化

鎖與Mark Word內(nèi)容

4.鎖的膨脹過(guò)程

對(duì)象的鎖會(huì)隨著競(jìng)爭(zhēng)情況逐漸升級(jí)眠蚂,但是不能降級(jí)煞聪。


鎖升級(jí)

前面簡(jiǎn)單通過(guò)文字描述了下 偏向鎖、輕量鎖逝慧、重量鎖的各自操作昔脯,不過(guò)還是一個(gè)完整的流程圖看著更為清晰啄糙。

如果還是不理解,強(qiáng)烈建議看下http://www.reibang.com/p/afa5296a4832云稚,這篇文章通過(guò)小故事來(lái)形象的解釋隧饼。

5.鎖的對(duì)比

6.最后

Synchronized實(shí)現(xiàn)原理,網(wǎng)上文章一大堆静陈,我也只是作為一個(gè)網(wǎng)絡(luò)知識(shí)的搬運(yùn)工燕雁,帶上的自己的理解,產(chǎn)出這篇文章鲸拥。其實(shí)自己也并不是100%的完全能說(shuō)清楚贵白,不過(guò)大致的流程算是知道了。如果碰到哪里不明白或者覺得哪里描述的有問(wèn)題的朋友崩泡,歡迎大家留言一起交流禁荒。


參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市角撞,隨后出現(xiàn)的幾起案子呛伴,更是在濱河造成了極大的恐慌,老刑警劉巖谒所,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件热康,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡劣领,警方通過(guò)查閱死者的電腦和手機(jī)姐军,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)尖淘,“玉大人奕锌,你說(shuō)我怎么就攤上這事〈迳” “怎么了惊暴?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)趁桃。 經(jīng)常有香客問(wèn)我辽话,道長(zhǎng),這世上最難降的妖魔是什么卫病? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任油啤,我火速辦了婚禮,結(jié)果婚禮上蟀苛,老公的妹妹穿的比我還像新娘益咬。我一直安慰自己,他們只是感情好屹逛,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布础废。 她就那樣靜靜地躺著汛骂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪评腺。 梳的紋絲不亂的頭發(fā)上帘瞭,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音蒿讥,去河邊找鬼蝶念。 笑死,一個(gè)胖子當(dāng)著我的面吹牛芋绸,可吹牛的內(nèi)容都是我干的媒殉。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼摔敛,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼廷蓉!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起马昙,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤桃犬,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后行楞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體攒暇,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年子房,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了形用。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡证杭,死狀恐怖田度,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情躯砰,我是刑警寧澤每币,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站琢歇,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏梦鉴。R本人自食惡果不足惜李茫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一慢逾、第九天 我趴在偏房一處隱蔽的房頂上張望淤刃。 院中可真熱鬧,春花似錦台盯、人聲如沸存筏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至予跌,卻和暖如春搏色,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背券册。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工频轿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人烁焙。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓航邢,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親骄蝇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子膳殷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348