白話 Synchronized

簡介

synchronize 關(guān)鍵字用起來非常簡單,但JDK1.6的底層實現(xiàn)卻很復(fù)雜。
JDK1.6開始JVM對synchronize底層做了優(yōu)化吭产。
上一篇
http://www.reibang.com/p/aeb0a68709cb

源代碼及部分注釋:
https://github.com/sparrowzoo/open-jdk8/blob/master/hotspot/src/share/vm/oops/markOop.hpp

Bit-format of an object header

 Bit-format of an object header (most significant first, big endian layout below):
//
//  32 bits:
//  --------
//             hash:25 ------------>| age:4    biased_lock:1 lock:2 (normal object)//MaxTenuringThreshold (GC次數(shù))最大為15
//             JavaThread*:23 epoch:2 age:4    biased_lock:1 lock:2 (biased object)//偏向
//             size:32 ------------------------------------------>| (CMS free block)
//             PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object) //晉升對象
//
//  64 bits:
//  --------
//  unused:25 hash:31 -->| unused:1   age:4    biased_lock:1 lock:2 (normal object)
//  JavaThread*:54 epoch:2 unused:1   age:4    biased_lock:1 lock:2 (biased object)
//  PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)
//  size:64 ----------------------------------------------------->| (CMS free block)
//
//  64 bits COOPS:
//  --------
//  unused:25 hash:31 -->| cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && normal object)
//  JavaThread*:54 epoch:2 cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && biased object)
//  narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object)
//  unused:21 size:35 -->| cms_free:1 unused:7 ------------------>| (COOPs && CMS free block)
//
  • hash (25/31)
    hash contains the identity hash value: largest value is
    31 bits, see os::random().  Also, 64-bit vm's require
    a hash value no bigger than 32 bits because they will not
    properly generate a mask larger than that: see library_call.cpp
    and c1_CodePatterns_sparc.cpp.

hash 是唯一的hash value,最大位是31bits,參見os::random().64位虛擬機也不可能生成大于32位的hash value.
hash_bits = max_hash_bits > 31 ? 31 : max_hash_bits

// Constants
  enum { age_bits                 = 4,
         lock_bits                = 2,
         biased_lock_bits         = 1,
         max_hash_bits            = BitsPerWord - age_bits - lock_bits - biased_lock_bits,
         hash_bits                = max_hash_bits > 31 ? 31 : max_hash_bits,(hash位數(shù))
         cms_bits                 = LP64_ONLY(1) NOT_LP64(0),
         epoch_bits               = 2
  };
  • age(4)

4位涤妒,因此MaxTenuringThreshold (GC次數(shù))最大為15

  • biased_lock(1)

1位,因為鎖標(biāo)記的兩位(01)代碼無鎖和偏向鎖爸舒,所以加一位來區(qū)分

  • lock(2)
    2 位,具體見下表
  • JavaThread指針
The runtime system aligns all JavaThread* pointers to
    a very large value (currently 128 bytes (32bVM) (7) or 256 (8) bytes (64bVM))
   to make room for the age bits & the epoch bits (used in support of
    biased locking), and for the CMS "freeness" bit in the 64bVM (+COOPs)

運行時會將JavaThread*以一個非常大的值對齊(128 bytes (32b vm) or 256 (64v VM),為了age bits epoch bits 以及壓縮指針的CMS freeness 位騰出空間稿蹲。

  • epoch(2)
    該字段為兩位扭勉,在鎖在起到的作用參見
    https://www.zhihu.com/question/56582060/answer/155398235
    簡單解析:
    對象每次初始化時(或者說被加偏向鎖時)會從類的頭信息中獲取該值,每加一次偏向鎖類的頭信息的值+1苛聘,同時對象的值也加+1涂炎,當(dāng)類的值超過4(2bits)時,那么該類將不適合偏向鎖设哗。
markOop incr_bias_epoch() {
    return set_bias_epoch((1 + bias_epoch()) & epoch_mask);
  }
  • 輕量鎖和重量鎖指針
    We assume that stack/thread pointers have the lowest two bits cleared.
    讓出鎖標(biāo)志兩位唱捣,所以該指為wordsize-2,因為 java 對象8字節(jié)對齊(3位),讓出兩位沒有問題网梢。

  • CMS
    其他字段為 cms gc相關(guān)震缭。

4個鎖級別

  1. 無鎖
 [header  |0 | 01]  unlocked           regular object header
[hashCode|age|0|01
  1. 偏向鎖
    the biased lock pattern is used to bias a lock toward a given thread. When this pattern is set in the low three bits, the lock is either biased toward a given thread or "anonymously" biased, indicating that it is possible for it to be biased. When the lock is biased toward a given thread, locking and unlocking can be performed by that thread without using atomic operations. When a lock's bias is revoked, it reverts back to the normal locking scheme described below.

the biased lock pattern 通常用于偏向指定的線程。當(dāng)這個模式的低三位被set時战虏,那么這個編向鎖可以指向指定的線程或 "anonymously" biased,來標(biāo)志這個對象可能被偏向鎖了拣宰,當(dāng)這個鎖被偏向提定的線程時,加鎖和解鎖都不需要原子操作烦感,當(dāng)鎖的偏向解除時徐裸,它恢復(fù)回原來的schema。
注:Synchronized 會保證可見性

 [JavaThread* | epoch | age | 1 | 01]       lock is biased toward given thread
 [0           | epoch | age | 1 | 01]       lock is anonymously biased
  1. 輕量級鎖
[ptr             | 00]  locked             ptr points to real header on stack

這時的指針指向stack 的對象頭

參考
https://pdfs.semanticscholar.org/bc8f/7a35b87b452924e180ed15b58f049bcac9db.pdf

light-lock-1.jpg
light-lock-2.jpg
  • 加鎖
    1. 為線程分配lock record
    2. copy object mark wordlock record
    3. 通過CAS啸盏,嘗試將object mark word的指針指向lock record,并將lock record owner的指針指向object mark word
  • 解鎖
    簡單理解就是加鎖的相反操作重贺,將object mark word的值從lock record 中還原。
Fast unlock atomically CASs displaced mark word
back into object header
> If success, no contention occurred
> If failed, monitor was inflated into heavyweight case
using OS-level locking primitives
> Enter run-time system, notify waiting threads`
  1. 重量級鎖
 [ptr             | 10]  monitor            inflated lock (header is wapped out)

指針指向monitor對象
在Java虛擬機(HotSpot)中,monitor是由ObjectMonitor實現(xiàn)的气笙,其主要數(shù)據(jù)結(jié)構(gòu)如下(位于HotSpot虛擬機源碼ObjectMonitor.hpp文件次企,C++實現(xiàn)的)

 // initialize the monitor, exception the semaphore, all other fields
  // are simple integers or pointers
  ObjectMonitor() {
    _header       = NULL;  //displaced object header word - mark
    _count        = 0;
    _waiters      = 0,     // number of waiting threads
    _recursions   = 0;
    _object       = NULL;  //backward object pointer - strong root
    _owner        = NULL;  //pointer to owning thread OR BasicLock
    _WaitSet      = NULL;  //LL of threads wait()ing on the monitor
    _WaitSetLock  = 0 ;
    _Responsible  = NULL ;
    _succ         = NULL ;
    _cxq          = NULL ;
    FreeNext      = NULL ;
    _EntryList    = NULL ; // number of waiting threads
    _SpinFreq     = 0 ;
    _SpinClock    = 0 ;
    OwnerIsThread = 0 ;
    _previous_owner_tid = 0;
  }
synchronous-lock.gif

由此可知

  1. 為什么Object.wait 和notify方法需要和Synchronized關(guān)鍵字配合使用。因為Object.wait將線程阻塞至Wait Set 對象潜圃,前提是已經(jīng)拿到鎖缸棵。
  2. Synchronized是一個非公平鎖。

GC標(biāo)志(不算鎖級別)

[ptr             | 11]  marked             used by markSweep to mark an object
                                               not valid at any other time

CMS GC相關(guān)內(nèi)容待整理

參考資料
http://ifeve.com/java-synchronized/

https://pdfs.semanticscholar.org/bc8f/7a35b87b452924e180ed15b58f049bcac9db.pdf

https://monkeysayhi.github.io/2018/01/02/%E6%B5%85%E8%B0%88%E5%81%8F%E5%90%91%E9%94%81%E3%80%81%E8%BD%BB%E9%87%8F%E7%BA%A7%E9%94%81%E3%80%81%E9%87%8D%E9%87%8F%E7%BA%A7%E9%94%81/

http://www.reibang.com/p/fd780ef7a2e8

簡書作者:
allanYan
http://www.reibang.com/p/ec28e3a59e80

占小狼
http://www.reibang.com/p/f4454164c017

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末谭期,一起剝皮案震驚了整個濱河市堵第,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌隧出,老刑警劉巖踏志,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異胀瞪,居然都是意外死亡针余,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進(jìn)店門凄诞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來圆雁,“玉大人,你說我怎么就攤上這事帆谍∥毙啵” “怎么了?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵汛蝙,是天一觀的道長烈涮。 經(jīng)常有香客問我,道長患雇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任宇挫,我火速辦了婚禮苛吱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘器瘪。我一直安慰自己翠储,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布橡疼。 她就那樣靜靜地躺著援所,像睡著了一般。 火紅的嫁衣襯著肌膚如雪欣除。 梳的紋絲不亂的頭發(fā)上住拭,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天,我揣著相機與錄音,去河邊找鬼滔岳。 笑死杠娱,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的谱煤。 我是一名探鬼主播摊求,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼刘离!你這毒婦竟也來了室叉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤硫惕,失蹤者是張志新(化名)和其女友劉穎茧痕,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疲憋,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡凿渊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了缚柳。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片埃脏。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖秋忙,靈堂內(nèi)的尸體忽然破棺而出彩掐,到底是詐尸還是另有隱情,我是刑警寧澤灰追,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布堵幽,位于F島的核電站,受9級特大地震影響弹澎,放射性物質(zhì)發(fā)生泄漏朴下。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一苦蒿、第九天 我趴在偏房一處隱蔽的房頂上張望殴胧。 院中可真熱鬧,春花似錦佩迟、人聲如沸团滥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽灸姊。三九已至,卻和暖如春秉溉,著一層夾襖步出監(jiān)牢的瞬間力惯,已是汗流浹背碗誉。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留夯膀,地道東北人诗充。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像诱建,于是被迫代替她去往敵國和親蝴蜓。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,446評論 2 348

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