Java中的鎖系列2

經(jīng)常聽到人家說什么偏向鎖、輕量級鎖刹衫、重量級鎖醋寝、自旋鎖搞挣,自適應(yīng)自旋鎖。每當(dāng)這個時候音羞,以前的我是一臉懵逼…


那到底什么是偏向鎖囱桨、輕量級鎖、自旋鎖和重量級鎖嗅绰?

首先我們需要明確一個概念舍肠,所有的這些鎖都是針對JVM的內(nèi)容對象鎖。是synchronized實現(xiàn)里相關(guān)的東西窘面。所以翠语,要了解這些鎖,我們必須要知道synchronized在JVM里的實現(xiàn)原理财边。

JVM基于進(jìn)入和退出Monitor對象來實現(xiàn)synchronized衬衬。在synchronized代碼塊開始位置織入monitorenter,在結(jié)束的位置(正常結(jié)束和異常結(jié)束處)織入monitorexit指令耿币。線程執(zhí)行到monitorenter處身堡,會獲取鎖對象鎖對應(yīng)的monitor的所有權(quán)侯养,即嘗試獲得對象的鎖。(任意對象都有一個monitor與之關(guān)聯(lián)鲸鹦,當(dāng)且一個monitor被持有后慧库,他處于鎖定狀態(tài))。

一馋嗜、對象里存了什么東西

既然是對象鎖齐板,那我肯定要知道對象是啥。

那java的對象結(jié)構(gòu)到底是什么樣子的呢葛菇?我們看下Hotspot JVM中甘磨,32位機(jī)器下,對象的存儲內(nèi)容眯停。


這個圖一定要仔細(xì)看下济舆。我們有時候也把第一個32位也叫MarkWord。

比如一個Integer對象莺债,實際大小是:4(MarkWord)+4(對象地址)+4(實際int值)+4(補全的對齊)滋觉。所以,下次人家問一個Integer占多少字節(jié)的時候齐邦,勇敢的說出來:16個字節(jié)椎侠,int的4倍。


二措拇、鎖的狀態(tài)和升級

從上面的圖中的MarkWord,我們可以知道一個對象有4種鎖的狀態(tài)我纪,由低到高依次為:無鎖狀態(tài)。偏向鎖、輕量級鎖浅悉、重量級鎖趟据,其實這些都是鎖的狀態(tài)。并且JVM還規(guī)定鎖的等級只可以升級仇冯,不可以降級之宿。這種鎖升級卻不能降級的策略族操,目的是為了提高獲得鎖和釋放鎖的效率苛坚。


三、偏向鎖

首先為什么要有偏向鎖色难?

偏向鎖是為了在無鎖競爭的情況下泼舱,避免在輕量級鎖獲取過程中執(zhí)行不必要的CAS原子指令,因為CAS原子指令雖然相對于重量級鎖來說開銷比較小但還是存在非臣侠颍可觀的本地延遲娇昙。

那偏向鎖是怎么做到減少CAS的原子指令的呢?

我們來看下偏向鎖的獲取和釋放流程:

1笤妙、線程A獲得鎖冒掌,會在線程A的的棧幀里創(chuàng)建lock record(鎖記錄變量),則在鎖對象的對象頭里和lock record里存儲線程A的線程id.以后該線程的進(jìn)入蹲盘,就不需要CAS操作股毫,只需要判斷是否是當(dāng)前線程。

2召衔、線程A獲取鎖后铃诬,不會主動釋放鎖。直到線程B也要競爭該鎖時苍凛,線程A才會釋放鎖趣席。

偏向鎖的釋放,需要等待全局安全點(在這個時間點上沒有正在執(zhí)行的字節(jié)碼)醇蝴,它會首先暫停擁有偏向鎖的線程宣肚,然后檢查持有偏向鎖的線程是否還活著,如果線程不處于活動狀態(tài)悠栓,則將對象頭設(shè)置成無鎖狀態(tài)霉涨。如果線程仍然活著,擁有偏向鎖的棧會被執(zhí)行闸迷,遍歷偏向?qū)ο蟮乃涗浨陡佟械逆i記錄和對象頭的Mark Word要么重新偏向其他線程,要么恢復(fù)到無鎖腥沽,或者標(biāo)記對象不適合作為偏向鎖逮走。最后喚醒暫停的線程。

JVM怎么開啟/關(guān)閉偏向鎖今阳?

偏向鎖在jdk1.6之后是默認(rèn)開啟的师溅。

通過jvm的參數(shù)-XX:-UseBiasedLocking,可以關(guān)閉偏向鎖茅信,然后默認(rèn)會進(jìn)入輕量級鎖。

通過jvm的參數(shù)-XX:+UseBiasedLocking

-XX:BiasedLockingStartupDelay=0墓臭,可以開啟偏向鎖蘸鲸,并且設(shè)置偏向鎖的啟動延遲為0(這個值默認(rèn)為5秒,因為jvm認(rèn)為系統(tǒng)剛剛啟動的時候資源競爭是很激烈的窿锉。我們把這個值改為0酌摇,方便測試。)

我們可以來看一下嗡载,開啟和關(guān)閉偏向鎖之后窑多,系統(tǒng)的差距


我們分別用兩個參數(shù)來運行這段代碼:

1、關(guān)閉偏向鎖洼滚。-XX:-UseBiasedLocking

運行結(jié)果如下:

2埂息、開啟偏向鎖。-XX:+UseBiasedLocking-XX:BiasedLockingStartupDelay=0

通過這個結(jié)果遥巴,我們可以大概的得出結(jié)論:在本例子中千康,完全無鎖的情況下,開啟偏向鎖比關(guān)閉偏向鎖铲掐,性能提升了5%到10%拾弃。


四、輕量級鎖

輕量級鎖(Lightweight Locking)本意是為了減少多線程進(jìn)入互斥的幾率迹炼,并不是要替代互斥砸彬。它利用CAS嘗試在進(jìn)入互斥前,進(jìn)行補救,避免調(diào)用操作系統(tǒng)層面的重量級互斥鎖斯入。

線程A獲得鎖砂碉,會在線程A的棧幀里創(chuàng)建lock

record(鎖記錄變量),讓lock record的指針指向鎖對象的對象頭中的mark word.再讓mark word指向lock record.這就是獲取了鎖刻两。

輕量級鎖增蹭,線程B在鎖競爭時,發(fā)現(xiàn)鎖已經(jīng)被線程A占用磅摹,則線程B不進(jìn)入內(nèi)核態(tài)滋迈,讓線程B自旋(自旋的事情我們后面再講),執(zhí)行空循環(huán)户誓,等待線程A釋放鎖饼灿。如果,完成自旋策略還是發(fā)現(xiàn)線程A沒有釋放鎖帝美,或者讓線程C占用了碍彭。則線程B試圖將輕量級鎖升級為重量級鎖。


五、重量級鎖

重量級鎖庇忌,就是讓爭搶鎖的線程從用戶態(tài)轉(zhuǎn)換成內(nèi)核態(tài)舞箍,讓CPU借助操作系統(tǒng)進(jìn)行線程協(xié)調(diào)。


六皆疹、自旋鎖

前面在講輕量級鎖的時候疏橄,我們已經(jīng)提到了自旋。本質(zhì)就是不讓出CPU略就,執(zhí)行空循環(huán)捎迫,然后等待拿鎖。

使用自旋鎖后残制,線程被掛起的幾率相對減少立砸,線程執(zhí)行的連貫性相對加強(qiáng)掖疮。因此初茶,對于那些鎖競爭不是很激烈,鎖占用時間很短的并發(fā)線程浊闪,具有一定的積極意義恼布。但是,對于鎖競爭激烈搁宾,單線程鎖占用很長時間的并發(fā)程序折汞,自旋鎖在自旋等待后,如果依然無法獲得對應(yīng)的鎖盖腿,反而浪費了系統(tǒng)的資源爽待。

我們來看下自己寫的一個自旋鎖。


在JDK1.6中翩腐,Java虛擬機(jī)提供-XX:+UseSpinning參數(shù)來開啟自旋鎖鸟款,使用-XX:PreBlockSpin參數(shù)來設(shè)置自旋鎖等待的次數(shù),默認(rèn)是10次茂卦。

在JDK1.7開始何什,自旋鎖的參數(shù)被取消,虛擬機(jī)不再支持由用戶配置自旋鎖等龙,自旋鎖總是會執(zhí)行处渣,自旋鎖次數(shù)也由虛擬機(jī)自動調(diào)整,也就是開始使用自適應(yīng)自旋鎖蛛砰。

七罐栈、自適應(yīng)自旋鎖

自適應(yīng)意味著自旋的次數(shù)或者時間不再是固定的,而是由前一次在同一個鎖上的自旋時間以及鎖擁有者的狀態(tài)來決定泥畅。如果在同一個鎖對象上,自旋等待剛好成功獲得鎖荠诬, 并且在持有鎖的線程在運行中,那么虛擬機(jī)就會認(rèn)為這次自旋也是很有可能獲得鎖, 進(jìn)而它將允許自旋等待相對更長的時間浅妆。


總結(jié):

這些東西可能在寫代碼的時候完全用不到望迎,正常情況下,只需要寫個synchronized就完事了凌外。但是辩尊,在虛擬機(jī)調(diào)優(yōu)方面還是很有用的。當(dāng)然康辑,面試的時候也很有用摄欲。


參考資料:

http://www.cnblogs.com/shangxiaofei/p/5569879.html

http://www.cnblogs.com/javaminer/p/3889023.html

http://www.cnblogs.com/think-in-java/p/5520462.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市疮薇,隨后出現(xiàn)的幾起案子胸墙,更是在濱河造成了極大的恐慌,老刑警劉巖按咒,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件迟隅,死亡現(xiàn)場離奇詭異,居然都是意外死亡励七,警方通過查閱死者的電腦和手機(jī)智袭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來掠抬,“玉大人吼野,你說我怎么就攤上這事×讲ǎ” “怎么了瞳步?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長腰奋。 經(jīng)常有香客問我单起,道長,這世上最難降的妖魔是什么氛堕? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任馏臭,我火速辦了婚禮,結(jié)果婚禮上讼稚,老公的妹妹穿的比我還像新娘括儒。我一直安慰自己,他們只是感情好锐想,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布帮寻。 她就那樣靜靜地躺著,像睡著了一般赠摇。 火紅的嫁衣襯著肌膚如雪固逗。 梳的紋絲不亂的頭發(fā)上浅蚪,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天,我揣著相機(jī)與錄音烫罩,去河邊找鬼惜傲。 笑死,一個胖子當(dāng)著我的面吹牛贝攒,可吹牛的內(nèi)容都是我干的盗誊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼隘弊,長吁一口氣:“原來是場噩夢啊……” “哼哈踱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起梨熙,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤开镣,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后咽扇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體邪财,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年肌割,在試婚紗的時候發(fā)現(xiàn)自己被綠了卧蜓。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡把敞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出榨惠,到底是詐尸還是另有隱情奋早,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布赠橙,位于F島的核電站耽装,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏期揪。R本人自食惡果不足惜掉奄,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望凤薛。 院中可真熱鬧姓建,春花似錦、人聲如沸缤苫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽活玲。三九已至涣狗,卻和暖如春谍婉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背镀钓。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工穗熬, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人丁溅。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓死陆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親唧瘾。 傳聞我的和親對象是個殘疾皇子措译,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354

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