在一个 32 bits 的机器中,普通对象的 Java 对象头由 Mark Word 和 Klass Word 组成,一共 64 bits:
1 2 3 4 5
|---------------------------------------------------------| | Object Header (64 bits) | |---------------------------------------------------------| | Mark Word (32 bits) | Klass Word (32 bits) | |---------------------------------------------------------|
其中的 Mark Word(标记字)主要用来表示对象的线程锁状态,另外还可以用来配合 GC、存放该对象的hashCode。对于一个重量级锁,它的 Mark Word 是
1 2 3 4 5
|---------------------------------------------------------| | Mark Word (32 bits) | |---------------------------------------------------------| | ptr_to_heavyweight_monitor(30 bits) | 1 0 | |---------------------------------------------------------|
// Cxq points to the the set of Recently Arrived Threads attempting entry. // Because we push threads onto _cxq with CAS, the RATs must take the form of // a singly-linked LIFO. We drain _cxq into EntryList at unlock-time when // the unlocking thread notices that EntryList is null but _cxq is != null. // * Contending threads "push" themselves onto the cxq with CAS // and then spin/park.
// Threads blocked on entry or reentry. // The EntryList is ordered by the prevailing queue discipline and // can be organized in any convenient fashion, such as a doubly-linked list or // a circular doubly-linked list. Critically, we want insert and delete operations // to operate in constant-time. If we need a priority queue then something akin // to Solaris' sleepq would work nicely. Viz., // http://agg.eng/ws/on10_nightly/source/usr/src/uts/common/os/sleepq.c. // Queue discipline is enforced at ::exit() time, when the unlocking thread // drains the cxq into the EntryList, and orders or reorders the threads on the // EntryList accordingly.
// QMode: // QMode == 1 : drain cxq to EntryList, reversing order // QMode == 2 : cxq has precedence over EntryList. // QMode == 3 : Aggressively drain cxq into EntryList at the first opportunity. // This policy ensure that recently-run threads live at the head of // EntryList. // QMode == 4 : Aggressively drain cxq into EntryList at the first opportunity. // This policy ensure that recently-run threads live at the head of // EntryList. // Aggressively drain cxq into EntryList at the first opportunity. // This policy ensure that recently-run threads live at the head of // EntryList.
_WaitSet
在得到 Monitor 锁后因为调用 wait() 方法而被挂起的线程会被放在该队列中。
等待时间到期后唤醒或者被其他线程唤醒。
1 2 3 4 5
// * Waiting threads reside on the WaitSet list -- wait() puts // the caller onto the WaitSet. // * notify() or notifyAll() simply transfers threads from the WaitSet to // either the EntryList or cxq. Subsequent exit() operations will // unpark the notifyee.
intObjectMonitor::TryLock(Thread * Self){ for (;;) { void * own = _owner ; // 如果已经有人得到锁了, 直接返回 if (own != NULL) return0 ;
// 获得锁成功 if (Atomic::cmpxchg_ptr (Self, &_owner, NULL) == NULL) {
// 要么保证 _recursions == 0, 要么设置 _recursions = 0。 assert (_recursions == 0, "invariant") ; assert (_owner == Self, "invariant") ; return1 ; } // The lock had been free momentarily, but we lost the race to the lock. // Interference -- the CAS failed. // We can either return -1 or retry. // Retry doesn't make as much sense because the lock was just acquired. if (true) return-1 ; } }