簡介
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個鎖級別
- 無鎖
[header |0 | 01] unlocked regular object header
[hashCode|age|0|01
- 偏向鎖
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
- 輕量級鎖
[ptr | 00] locked ptr points to real header on stack
這時的指針指向stack 的對象頭
參考
https://pdfs.semanticscholar.org/bc8f/7a35b87b452924e180ed15b58f049bcac9db.pdf
- 加鎖
- 為線程分配lock record
- copy
object mark word
到lock record
- 通過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`
- 重量級鎖
[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;
}
由此可知
- 為什么Object.wait 和notify方法需要和Synchronized關(guān)鍵字配合使用。因為Object.wait將線程阻塞至Wait Set 對象潜圃,前提是已經(jīng)拿到鎖缸棵。
- 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
http://www.reibang.com/p/fd780ef7a2e8