學(xué)會synchronized(從偏向鎖到重量級鎖)

注:無論是對一個對象進(jìn)行加鎖還是對一個方法進(jìn)行加鎖油挥,實際上都是對對象進(jìn)行加鎖腺毫。
java對象在內(nèi)存中的存儲結(jié)構(gòu)主要有一下三個部分:

  1. 對象頭
  2. 實例數(shù)據(jù)
  3. 填充數(shù)據(jù)

這里強(qiáng)調(diào)一下库快,對象頭里的數(shù)據(jù)主要是一些運(yùn)行時的數(shù)據(jù)晤硕。
其簡單的結(jié)構(gòu)如下

從該表格中我們可以看到悼潭,對象中關(guān)于鎖的信息是存在Markword里的
當(dāng)我們創(chuàng)建一個對象LockObject時,該對象的部分Markword關(guān)鍵數(shù)據(jù)如下:

從圖中可以看出舞箍,偏向鎖的標(biāo)志位是“01”舰褪,狀態(tài)是“0”,表示該對象還沒有被加上偏向鎖疏橄。(“1”是表示被加上偏向鎖)占拍。該對象被創(chuàng)建出來的那一刻,就有了偏向鎖的標(biāo)志位,這也說明了所有對象都是可偏向的刷喜,但所有對象的狀態(tài)都為“0”,也同時說明所有被創(chuàng)建的對象的偏向鎖并沒有生效立砸。

偏向鎖:

  • 偏向鎖是jdk1.6以后引入的一項鎖優(yōu)化掖疮,其中的“偏”其實是偏心的偏。它的意思是說颗祝,這個鎖會偏向于第一個獲取它的線程浊闪,在接下來的執(zhí)行過程中,假如該鎖沒有其他線程獲取螺戳,也沒有其他線程競爭搁宾,那么持有偏向鎖的線程永遠(yuǎn)不需要進(jìn)行同步操作。
  • 偏向鎖是針對一個線程而言的倔幼,線程獲取鎖以后就不需要再有解鎖等操作了盖腿,這樣可以省去很多開銷。假如有兩個以上的線程競爭該鎖损同,那么偏向鎖就失效了翩腐,進(jìn)而升級為輕量級鎖(自旋鎖)
    為什么會這樣做呢?因為經(jīng)驗表明膏燃,其實大部分情況下茂卦,都是同一個線程進(jìn)入同一塊同步代碼塊的,這也是設(shè)計偏向鎖的原因
    在Jdk1.6中组哩,偏向鎖的開關(guān)是默認(rèn)開啟的等龙,適用于只有一個線程訪問同步塊的場景。

鎖膨脹

假如有兩個以上的線程競爭該鎖伶贰,那么偏向鎖就失效了蛛砰,進(jìn)而升級為輕量級鎖(自旋鎖)。這就是所謂的鎖膨脹

鎖撤銷

由于偏向鎖失效了幕袱,接下來就需要把該鎖撤銷暴备。撤銷鎖的代價還是挺大的,其大概的過程如下:

  • 在一個安全點停止擁有該鎖的線程
  • 遍歷線程棧们豌,如果存在鎖記錄的話涯捻,需要修復(fù)鎖記錄和Markword,使其變成無鎖狀態(tài)
  • 喚醒當(dāng)前線程望迎,將當(dāng)前鎖升級為輕量級鎖(自旋鎖)
    所以障癌,如果某些同步代碼塊大多數(shù)情況下都是兩個及以上線程競爭的話,那么偏向鎖就是一種累贅辩尊。對于這種情況涛浙,應(yīng)該一開始就把偏向鎖這個功能關(guān)閉

輕量級鎖(樂觀鎖、非阻塞同步)

鎖撤銷升級為輕量級鎖之后,相應(yīng)的Markword也會進(jìn)行相應(yīng)的變化轿亮。鎖撤銷后升級為輕量級鎖的過程如下:

  • 線程在自己的棧幀中創(chuàng)建鎖記錄LockRecord疮薇。
  • 將鎖對象的對象頭中的MarkWord復(fù)制到線程的剛剛創(chuàng)建的鎖記錄中。
  • 將鎖記錄中的Owner指針指向鎖對象我注。
  • 將鎖對象的對象頭的MarkWord替換為指向鎖記錄的指針按咒。
    注:鎖標(biāo)志位”00”表示輕量級鎖
    輕量級鎖主要有兩種
  • 自旋鎖
  • 自適應(yīng)自旋鎖

自旋鎖

所謂自旋,就是當(dāng)有另外一個線程來競爭鎖時但骨,這個線程會在原地循環(huán)等待励七,而不是把線程阻塞,直到那個線程獲得鎖的線程釋放鎖之后奔缠,這個線程馬上就可以獲得該鎖掠抬。
注意:鎖在原地循環(huán)的時候,是會消耗CPU的校哎,就相當(dāng)于在執(zhí)行一個什么都沒有的for循環(huán)两波。
所以,輕量級鎖適用于那些同步代碼塊執(zhí)行很快的場景贬蛙,這樣雨女,原地自旋的線程只需要等待很短的時間就可以獲取鎖了。
經(jīng)驗表明阳准,大部分同步代碼塊執(zhí)行的時間都是很短的氛堕,也正是由于這個原因,才有了輕量級鎖

自旋鎖會帶來的一些問題

  • 如果同步代碼塊執(zhí)行很慢野蝇,需要消耗大量的時間讼稚,那么這時其他線程會在原地等待很久,消耗CPU
  • 本來一個線程把鎖釋放以后绕沈,當(dāng)前線程是能獲取到鎖的锐想。但是假如這個時候有好幾個線程都在競爭這個鎖的話,那么有可能當(dāng)前的線程就獲取不到鎖了乍狐,還需要繼續(xù)原地等待消耗CPU赠摇,甚至有可能一直獲取不到鎖
    基于這個問題,我們必須給線程的循環(huán)次數(shù)設(shè)置一個次數(shù)浅蚪,當(dāng)線程自旋超過這個次數(shù)藕帜,我們就認(rèn)為繼續(xù)自旋就不合適了,此時鎖會再次膨脹惜傲,升級為重量級鎖(互斥鎖)
  • 默認(rèn)情況下洽故,自旋的次數(shù)為10次,用戶可以通過-XX:PreBlockSpin來進(jìn)行更改盗誊。
  • 自旋鎖是在jdk1.4.2引入的

自適應(yīng)自旋鎖

所謂自適應(yīng)自旋鎖就是線程空循環(huán)等待的自旋次數(shù)并非是固定的时甚,而是會動態(tài)著根據(jù)實際情況來改變自旋等待的次數(shù)
其大概原理是這樣的:
假如一個線程1剛剛成功獲得一個鎖隘弊,當(dāng)它把鎖釋放了之后,線程2獲得該鎖荒适,并且線程2在運(yùn)行的過程中梨熙,此時線程1又想來獲得該鎖了,但線程2還沒有釋放該鎖刀诬,所以線程1只能自旋等待串结,但是虛擬機(jī)認(rèn)為,由于線程1剛剛獲得過該鎖舅列,那么虛擬機(jī)覺得線程1這次自旋也是很有可能能夠再次成功獲得該鎖的,所以會延長線程1自旋的次數(shù)卧蜓。
另外帐要,如果對于某一個鎖,一個線程自旋之后弥奸,很少成功獲得該鎖榨惠,那么以后這個線程要獲取該鎖時,是有可能直接忽略掉自旋過程盛霎,直接升級為重量級鎖的赠橙,以免空循環(huán)等待浪費資源。
輕量級鎖也被稱為非阻塞同步愤炸、樂觀鎖期揪,因為這個過程并沒有把線程阻塞掛起,而是讓線程空循環(huán)等待规个,串行執(zhí)行凤薛。

重量級鎖(互斥鎖、阻塞同步诞仓、悲觀鎖)

輕量級鎖膨脹之后缤苫,就升級為重量級鎖了。重量級鎖是依賴對象內(nèi)部的monitor鎖來實現(xiàn)的墅拭,而monitor又依賴操作系統(tǒng)的MutexLock(互斥鎖)來實現(xiàn)的活玲,所以重量級鎖也叫互斥鎖。
當(dāng)輕量級鎖經(jīng)過鎖撤銷等步驟升級為重量級鎖之后谍婉,他的Markword部署數(shù)據(jù)體如下:

為什么說重量級鎖開銷大

主要是舒憾,當(dāng)線程檢測到鎖是重量級鎖之后,會把等待獲取鎖的線程阻塞屡萤,被阻塞的線程不會消耗CPU珍剑。但是阻塞或者喚醒一個線程時都要操作系統(tǒng)來幫忙,這就需要從用戶態(tài)切換到內(nèi)核態(tài)死陆,而切換狀態(tài)是需要消耗很多時間的招拙,有時可能比用戶執(zhí)行代碼的時間還要長唧瘾,這就是為什么說重量級鎖開銷很大。

總結(jié)

通過上面的分析别凤,我們知道了為什么synchronized關(guān)鍵字為何又深得人心饰序,也知道了鎖的演變過程。
也就是說规哪,synchronized關(guān)鍵字并非一開始就該對象加上重量級鎖求豫,也是從偏向鎖,輕量級鎖诉稍,再到重量級鎖的過程蝠嘉。

這個過程也告訴我們,假如我們一開始就知道某個同步代碼塊的競爭很激烈杯巨、很慢的話蚤告,那么我們一開始就應(yīng)該使用重量級鎖了,從而省掉一些鎖轉(zhuǎn)換的開銷服爷。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末杜恰,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子仍源,更是在濱河造成了極大的恐慌心褐,老刑警劉巖,帶你破解...
    沈念sama閱讀 223,002評論 6 519
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件笼踩,死亡現(xiàn)場離奇詭異逗爹,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)嚎于,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,357評論 3 400
  • 文/潘曉璐 我一進(jìn)店門桶至,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人匾旭,你說我怎么就攤上這事镣屹。” “怎么了价涝?”我有些...
    開封第一講書人閱讀 169,787評論 0 365
  • 文/不壞的土叔 我叫張陵女蜈,是天一觀的道長。 經(jīng)常有香客問我色瘩,道長伪窖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,237評論 1 300
  • 正文 為了忘掉前任居兆,我火速辦了婚禮覆山,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘泥栖。我一直安慰自己簇宽,他們只是感情好勋篓,可當(dāng)我...
    茶點故事閱讀 69,237評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著魏割,像睡著了一般譬嚣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上钞它,一...
    開封第一講書人閱讀 52,821評論 1 314
  • 那天拜银,我揣著相機(jī)與錄音,去河邊找鬼遭垛。 笑死尼桶,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的锯仪。 我是一名探鬼主播疯汁,決...
    沈念sama閱讀 41,236評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼卵酪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起谤碳,我...
    開封第一講書人閱讀 40,196評論 0 277
  • 序言:老撾萬榮一對情侶失蹤溃卡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蜒简,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瘸羡,經(jīng)...
    沈念sama閱讀 46,716評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,794評論 3 343
  • 正文 我和宋清朗相戀三年搓茬,在試婚紗的時候發(fā)現(xiàn)自己被綠了犹赖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,928評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡卷仑,死狀恐怖峻村,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情锡凝,我是刑警寧澤粘昨,帶...
    沈念sama閱讀 36,583評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站窜锯,受9級特大地震影響张肾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜氢惋,卻給世界環(huán)境...
    茶點故事閱讀 42,264評論 3 336
  • 文/蒙蒙 一娜亿、第九天 我趴在偏房一處隱蔽的房頂上張望芹缔。 院中可真熱鬧,春花似錦芍秆、人聲如沸惯疙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,755評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽螟碎。三九已至,卻和暖如春迹栓,著一層夾襖步出監(jiān)牢的瞬間掉分,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,869評論 1 274
  • 我被黑心中介騙來泰國打工克伊, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留酥郭,地道東北人。 一個月前我還...
    沈念sama閱讀 49,378評論 3 379
  • 正文 我出身青樓愿吹,卻偏偏與公主長得像不从,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子犁跪,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,937評論 2 361

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