synchronized實現(xiàn)原理和鎖優(yōu)化

  1. ObjectMonitor

在HotSpot中钾军,Monitor采用ObjectMonitor實現(xiàn)窒舟。

Monitor是一個同步工具嘲驾,通常被描述為一個對象淌哟。每一個Java對象都擁有一把看不見的Monitor鎖
Java中每個對象都擁有的監(jiān)視器用來監(jiān)測并發(fā)代碼的重入距淫,在非多線程編碼時Monitor監(jiān)視器不起作用绞绒,在synchronized范圍內,監(jiān)視器發(fā)揮作用榕暇。

ObjectMonitor的結構

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

2.synchronized實現(xiàn)原理

synchronized在軟件層面依賴JVM虛擬機實現(xiàn)同步;JUC包中的Lock同步鎖在硬件層面依賴特殊的CPU指令實現(xiàn)同步狰晚。

synchronized通過Monitor來實現(xiàn)線程同步筒饰,Monitor依賴于底層的操作系統(tǒng)的Mutex Lock(互斥鎖)來實現(xiàn)的線程同步
依賴底層操作系統(tǒng)的Mutex Lock所實現(xiàn)的鎖稱之為重量級鎖壁晒。

同步代碼塊的同步原理
synchronized同步代碼塊代碼生成的字節(jié)碼指令中包含monitorentermonitorexit指令瓷们。
monitorenter指令:執(zhí)行該指令時可以嘗試去獲取對象的monitor鎖。當獲得monitor時就會處于鎖定狀態(tài)秒咐,就可以去執(zhí)行同步代碼塊谬晕。
monitorexit指令:執(zhí)行該指令會退出同步代碼塊并釋放鎖。執(zhí)行該指令的線程是monitor的占有者携取。

異常退出同步代碼塊時會釋放鎖攒钳,也會調用該指令。

同步方法的同步原理
同步方法的字節(jié)碼指令中沒有monitorentermonitorexit指令雷滋,是通過方法修飾符上的ACC_SYNCHRONIZED標識符來實現(xiàn)方法的同步不撑。

同步方法是一種隱式的方式實現(xiàn)同步,不需要字節(jié)碼指令來完成晤斩。
同步代碼塊中monitorentermonitorexit指令的執(zhí)行是JVM通過調用操作系統(tǒng)的互斥語句mutex實現(xiàn)的焕檬,被阻塞的線程會被掛起、等待重新調度澳泵,會導致在用戶態(tài)和內核態(tài)切換实愚。

  1. Java對象的對象頭

在HotSpot虛擬機中,對象在內存中的存儲的布局可以分為3塊區(qū)域:對象頭兔辅、實例數(shù)據(jù)爆侣、對齊填充

Java對象頭
對象頭包括兩部分信息:Mark Word和類型指針幢妄。
Mark Word是實現(xiàn)輕量級鎖和偏向鎖的關鍵。

類型指針:指向對象的類元數(shù)據(jù)的指針茫负。
Mark Word:用于存儲對象自身的運行時數(shù)據(jù)蕉鸳,是實現(xiàn)輕量級鎖和偏向鎖的關鍵
包括哈希碼忍法、GC分代年齡潮尝、鎖狀態(tài)標志線程持有的鎖饿序、偏向線程ID勉失、偏向時間戳。
是一個非固定的數(shù)據(jù)結構用以方便在小的空間存儲更多的信息原探。
會根據(jù)對象的狀態(tài)復用自己的存儲空間乱凿,就是說在運行期間Mark Work里存儲的數(shù)據(jù)會隨著鎖標志位的變化而變化顽素。

不同狀態(tài)下Mark Word的結構
  1. Lock Record --鎖記錄

Lock Record(鎖記錄):在線程的棧中創(chuàng)建,用來存儲鎖對象的Mark Word的拷貝徒蟆。
線程私有的數(shù)據(jù)結構胁出,每一個線程都有一個可用的Lock Record列表。
每一個被鎖住的對象都會和一個Lock Record關聯(lián)段审,對象頭中的Mark Word指向Lock Record的起始地址全蝶,

LockRecord的結構如下圖

Lock Record的結構.png

Owner:當線程成功獲得鎖后存放線程的唯一標識寺枉。
EnterQ:關聯(lián)一個互斥鎖抑淫,阻塞所有競爭鎖失敗的線程。
RcThis:表示在該線程獲得的鎖上blocked或waiting的所有線程的個數(shù)姥闪。
Nest:重入鎖的計數(shù)始苇。
HashCode:保存從對象頭拷貝過來的HashCode值(可能包含GC age)。
Candidate:只有兩種值:0或1甘畅,表示沒有需要喚醒的線程或表示要喚醒一個線程去競爭鎖埂蕊。

  1. 對synchronized實現(xiàn)機制進行的鎖優(yōu)化

依賴操作系統(tǒng)Mutex Lock所實現(xiàn)的重量級鎖在線程切換時會導致在用戶態(tài)和內核態(tài)之間切換,會導致很大的開銷疏唾。
JDK6之后蓄氧,引入了偏向鎖輕量級鎖來減少鎖操作的開銷。
目前鎖一共有4種狀態(tài)槐脏,級別從低到高依次為:無鎖喉童、偏向鎖、輕量級鎖顿天、重量級鎖堂氯;鎖狀態(tài)只能升級不能降級
偏向鎖牌废、輕量級鎖屬于樂觀鎖咽白,重量級鎖屬于悲觀鎖。樂觀鎖CAS的實現(xiàn)同步鸟缕,獲取不到時會轉換為悲觀鎖晶框。

無鎖
沒有對資源進行鎖定,所有線程都可以訪問并修改同一個資源懂从,但只有一個線程可以修改成功授段。
特點:修改操作在循環(huán)中進行。
CAS原理及應用即是無鎖的實現(xiàn)番甩。

偏向鎖
偏向于第一個訪問鎖的線程侵贵,如果在運行過程中,鎖沒有被其他線程訪問缘薛,持有偏向鎖的線程永遠不會觸發(fā)同步窍育。
偏向鎖就是為了解決在不存在多線程競爭時卡睦,鎖總是由同一個線程多次獲得的情況。目的是在只有一個線程執(zhí)行同步代碼塊時可以提高性能蔫骂。

加鎖過程
a.加鎖發(fā)生在鎖第一次被線程擁有時么翰,會使用CAS原子操作嘗試更新對象的Mark Word,將Mark Word中的偏向鎖標志位改為1辽旋,并記錄偏向線程的ID浩嫌。
之后在對象頭中的偏向線程ID指向的線程進入和退出相同鎖對象的同步代碼塊時不用通過CAS操作來更新對象頭。
撤銷和膨脹過程
b.另一個競爭線程想要進入同步代碼塊時补胚,訪問到Mark Word中偏向鎖標志為1码耐,確認是可偏向狀態(tài);同時檢查到對象頭中的偏向線程ID與該競爭線程不一致溶其,競爭線程嘗試進行CAS操作更新對象頭骚腥。
c.競爭線程更新對象頭失敗時,等待持有偏向鎖線程進入安全點(會導致STW)并暫停持有偏向鎖的線程瓶逃,根據(jù)偏向鎖線程是否處于同步代碼塊束铭,處于同步代碼塊時將偏向鎖升級為輕量級鎖;已經退出同步代碼塊時厢绝,將鎖置為無鎖狀態(tài)契沫。
d.競爭線程更新對象頭成功時,直接進入同步代碼塊昔汉。

偏向鎖加鎖撤銷鎖流程圖:

偏向鎖.png

適合在無鎖競爭情況下使用懈万,撤銷偏向鎖時會導致stop the world

問題:為什么在到達全局安全點時才會進行偏向鎖的釋放靶病?
Epoch有關会通。

輕量級鎖
輕量級鎖是為了在線程交替執(zhí)行同步代碼塊時提高性能,偏向鎖是在只有一個線程執(zhí)行同步塊時提高性能娄周。
輕量級鎖與偏向鎖的不同:輕量級鎖每次退出同步代碼塊都要釋放鎖涕侈,偏向鎖只有在競爭發(fā)生時才會釋放鎖。

加鎖過程
a.線程進入同步代碼塊時確定對象鎖狀態(tài):即對象鎖狀態(tài)是無鎖狀態(tài):對象頭中Mark Word中的鎖標志位為:“01”狀態(tài)煤辨,偏向鎖標志位為:“0”驾凶。
b.確定對象鎖的對象頭為無鎖狀態(tài)后,在當前線程的棧幀中創(chuàng)建鎖記錄(Lock Record)空間掷酗,將鎖對象對象頭中的Mark Word復制到鎖記錄中
c.Mark Word保存到鎖記錄成功后窟哺,使用CAS操作嘗試將對象的Mark Word更新為指向Lock Record的指針并將Lock Record鎖記錄里的owner指向對象的Mark Word泻轰。
CAS操作成功了:線程就擁有了對象的鎖可以去執(zhí)行同步代碼塊,并會將對象的鎖標志設置為:“00”且轨,即為輕量級鎖浮声。
CAS操作失敗了:先檢查對象頭Mark Word的指針有沒有指向當前線程的鎖記錄Lock Record虚婿,指向了說明當前線程已經獲得了鎖,本次加鎖是重入鎖泳挥,當前線程可以直接進入同步塊繼續(xù)執(zhí)行然痊;否則線程會進入自旋狀態(tài),不斷嘗試去獲取鎖屉符。

  • 輕量級鎖每次進入與退出同步塊時都要通過CAS操作更新對象頭剧浸。

鎖釋放過程
d.線程退出同步代碼塊并釋放鎖是通過CAS操作來完成的,會用CAS操作將對象頭中的Mark Word中記錄的鎖對象的指針替換為鎖記錄中復制的Mark Word矗钟。
CAS操作成功:同步操作完成唆香,對象頭設置為無鎖狀態(tài)(偏向鎖為:“0”,鎖標志位為:“01”)吨艇。
CAS操作失敗:此時持有輕量級鎖的線程會將鎖釋放躬它,喚醒阻塞的線程。
CAS操作失敗的原因:是因為沒有得到鎖的線程在超過了自旋次數(shù)還沒有獲得鎖东涡,進入阻塞狀態(tài)冯吓,并將對象頭的鎖標志更改為:“10”(重量級鎖),Mark Word中存儲的是指向指向重量級鎖的指針(互斥量)疮跑。

獲得和釋放輕量級鎖的過程圖如下:

獲得和釋放輕量級鎖的過程圖.png

問題1:為什么在升級為輕量級鎖時要把對象頭里的Mark Word復制到線程棧的鎖記錄中组贺?
在獲得鎖時:會將Mark Word值作為CAS比較的條件(CAS操作的三個值中的當前值)。只有鎖記錄復制的Mark Word值與對象鎖的對象頭中的Mark Word相等時祸挪,才會將對象頭中的Mark Word中的內容替換為指向鎖記錄的指針锣披,才可以獲得鎖。
在釋放鎖時:通過該Mark Word可以判定是否在持有鎖的過程中該對象鎖被其他線程申請過贿条,如果被申請過雹仿,則在釋放鎖的過程中喚醒被掛起的線程。

問題2:為什么會嘗試CAS不成功以及什么情況下會不成功整以?

重量級鎖
如果在存在同一時間訪問同一鎖胧辽,就會導致輕量級鎖膨脹為重量級鎖。

對象鎖升級為重量級鎖時公黑,鎖標志的狀態(tài)值變?yōu)?10"邑商,Mark Word中存儲的是指向重量級鎖的指針(指針指向的是Monitor對象的起始地址),此時等待鎖的線程都會進入阻塞狀態(tài)凡蚜。

重量級鎖通過對象內部的monitor監(jiān)視器鎖來實現(xiàn)人断。監(jiān)視器鎖是依賴于底層操作系統(tǒng)的Mutex Lock(互斥鎖)來實現(xiàn)。

總結:偏向鎖是通過對比Mark Word解決加鎖問題朝蜘,避免多次執(zhí)行CAS操作恶迈;輕量級鎖通過CAS操作和自旋解決加鎖問題,避免線程阻塞和喚醒而影響性能谱醇;重量級鎖是將除了擁有鎖的線程以外的線程都阻塞暇仲。

  1. 對synchronized實現(xiàn)機制進行的其他調整

鎖消除
在進行同步控制時步做,JVM檢測到不可能存在共享數(shù)據(jù)競爭,JVM就會對同步鎖進行鎖清除奈附。
鎖清除的依據(jù)是:逃逸分析的數(shù)據(jù)支持全度。

鎖粗化
將多個連續(xù)的加鎖、解鎖操作連接在一起斥滤,擴展成一個范圍更大的鎖将鸵。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市中跌,隨后出現(xiàn)的幾起案子咨堤,更是在濱河造成了極大的恐慌,老刑警劉巖漩符,帶你破解...
    沈念sama閱讀 222,378評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件一喘,死亡現(xiàn)場離奇詭異,居然都是意外死亡嗜暴,警方通過查閱死者的電腦和手機凸克,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來闷沥,“玉大人萎战,你說我怎么就攤上這事∮咛樱” “怎么了蚂维?”我有些...
    開封第一講書人閱讀 168,983評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長路狮。 經常有香客問我虫啥,道長,這世上最難降的妖魔是什么奄妨? 我笑而不...
    開封第一講書人閱讀 59,938評論 1 299
  • 正文 為了忘掉前任涂籽,我火速辦了婚禮,結果婚禮上砸抛,老公的妹妹穿的比我還像新娘评雌。我一直安慰自己,他們只是感情好直焙,可當我...
    茶點故事閱讀 68,955評論 6 398
  • 文/花漫 我一把揭開白布景东。 她就那樣靜靜地躺著,像睡著了一般奔誓。 火紅的嫁衣襯著肌膚如雪斤吐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,549評論 1 312
  • 那天,我揣著相機與錄音曲初,去河邊找鬼。 笑死杯聚,一個胖子當著我的面吹牛臼婆,可吹牛的內容都是我干的。 我是一名探鬼主播幌绍,決...
    沈念sama閱讀 41,063評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼颁褂,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了傀广?” 一聲冷哼從身側響起颁独,我...
    開封第一講書人閱讀 39,991評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎伪冰,沒想到半個月后誓酒,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 46,522評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡贮聂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,604評論 3 342
  • 正文 我和宋清朗相戀三年靠柑,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吓懈。...
    茶點故事閱讀 40,742評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡歼冰,死狀恐怖,靈堂內的尸體忽然破棺而出耻警,到底是詐尸還是另有隱情隔嫡,我是刑警寧澤,帶...
    沈念sama閱讀 36,413評論 5 351
  • 正文 年R本政府宣布甘穿,位于F島的核電站腮恩,受9級特大地震影響,放射性物質發(fā)生泄漏扒磁。R本人自食惡果不足惜庆揪,卻給世界環(huán)境...
    茶點故事閱讀 42,094評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望妨托。 院中可真熱鬧缸榛,春花似錦、人聲如沸兰伤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽敦腔。三九已至均澳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背找前。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評論 1 274
  • 我被黑心中介騙來泰國打工糟袁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人躺盛。 一個月前我還...
    沈念sama閱讀 49,159評論 3 378
  • 正文 我出身青樓项戴,卻偏偏與公主長得像,于是被迫代替她去往敵國和親槽惫。 傳聞我的和親對象是個殘疾皇子周叮,可洞房花燭夜當晚...
    茶點故事閱讀 45,747評論 2 361

推薦閱讀更多精彩內容

  • 本文是我自己在秋招復習時的讀書筆記,整理的知識點界斜,也是為了防止忘記仿耽,尊重勞動成果,轉載注明出處哦各薇!如果你也喜歡项贺,那...
    波波波先森閱讀 11,273評論 4 56
  • 線程安全敬扛,是Java并發(fā)編程中的重要關注點,應該注意到的是朝抖,造成線程安全問題的主要原因有兩點:1啥箭,存在共享數(shù)據(jù)(也...
    _Zy閱讀 8,558評論 3 16
  • 該文章屬于《Java并發(fā)編程》系列文章,如果想了解更多治宣,請點擊《Java并發(fā)編程之總目錄》 前言 上篇文章我們講了...
    AndyJennifer閱讀 1,424評論 7 2
  • 20180820—20180826周得到 〈19周〉 文|過云雨 壹|偏見 好像每個本地人對于其他省份都會有一些偏...
    過云雨Milo閱讀 246評論 0 0
  • 說到對一個城市的印象我們多半會回憶起什么急侥?這個城市的環(huán)境,這個城市的美食侮邀,這個城市的交通坏怪,這個城市的人文,最終構...
    麋的鹿閱讀 387評論 0 1