写在前面:

本人在学习 Java 并发编程时,对于 synchronized 关键字最底层的重量级锁 Monitor 的实现过程兴趣颇高,所以写下这篇文章记录学习过程。但碍于学识浅薄,文章中难免会出现错误,恳请各位读者加以指正。

文章末尾有本人根据源码分析得出的获取 Monitor 流程图,点击此处跳转

主要参考资料:

  1. ObjectMonitor 头文件:jdk8.runtime.objectMonitor.hpp
  2. ObjectMonitor 源文件:jdk8.runtime.objectMonitor.cpp
  3. 知乎:深入底层源码 - 深度理解 synchronized 原理
  4. Java多线程-对象内置锁(ObjectMonitor

Java 的对象头结构

首先我们先回顾一下关于 Java 的对象头结构。

在一个 32 bits 的机器中,普通对象的 Java 对象头由 Mark WordKlass 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 |
|---------------------------------------------------------|

这个“重量级锁”指的是底层的 ObjectMonitor 对象,其包含着对 synchronized 实现”加锁“的底层操作,是整个 synchronized 的核心。与此同时,ObjectMonitor 也是 Java 基础对象 Objectwait(), notify() 方法的底层支持实现。

ObjectMonitor 对象

接下来我们开始研究 ObjectMonitor 对象的构造器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// initialize the monitor, exception the semaphore, all other fields
// are simple integers or pointers
ObjectMonitor() {
_header = NULL; // Mark Word
_count = 0; // 等待的线程计数,|_WaitSet| + |_EntryList|
// reference count to prevent reclaimation/deflation
// at stop-the-world time. See deflate_idle_monitors().
// _count is approximately |_WaitSet| + |_EntryList|
_waiters = 0; // 等待线程数
_recursions = 0; // 递归;线程的重入次数: void reenter(intptr_t recursions, TRAPS);
_object = NULL; // 对应 synchronized (object)对应里面的object
_owner = NULL; // 指向拥有该 monitor 的线程。
_WaitSet = NULL; // 因为调用object.wait()方法而被阻塞的线程会被放在该队列中
_WaitSetLock = 0 ;
_Responsible = NULL;
_succ = NULL;
_cxq = NULL; // 竞争队列,所有请求锁的线程首先会被放在这个队列中
FreeNext = NULL;
_EntryList = NULL; // 阻塞;第二轮竞争锁仍然没有抢到的线程
// (在exit之后扔没有竞争到的线程将有可能会被同步至此)
_SpinFreq = 0;
_SpinClock = 0;
OwnerIsThread = 0;
_previous_owner_tid = 0;
}

这里我们需要了解以下几个成员变量的含义及作用:

_owner

官方文档中对于 _owner 的定义如下(截取)

1
2
// * A thread acquires ownership of a monitor by successfully
// CAS()ing the _owner field from null to non-null.
  • 初始时为 null。当有线程占有该 monitor 时,owner 标记为该线程的唯一标识。当线程释放 monitor时,owner又恢复为 nullowner 是一个临界资源,JVM 通过 CAS 操作来保证其线程安全的。

_cxq

官方文档中对于 _cxq 的定义如下(截取)

1
2
3
4
5
6
//   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.
  • 我们可以看出,线程刚到达时,想请求锁但都没有获得锁,那么这些线程被放在 _cxq 队列中竞争。所以这是一个临界资源
  • _cxq 是一个后进先出 LIFO 的单向链表(栈),所有请求锁的最新到达线程 RATs 首先会被放在这个队列中,_cxq 是一个临界资源,JVM 通过 CAS 原子指令来将 ObjectWaiter 写入队列的头部。

_EntryList

同样的,我们截取官方文档中对于 _EntryList 的定义如下

1
2
3
4
5
6
7
8
9
10
//   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.
  • Monitor 锁已经被一个线程获得时,其他想要获取 Monitor 锁的线程就需要进入 EntryList 阻塞等待。

  • EntryList 中的线程对象来自 _cxq_WaitSet,它们都要在 EntryList 中排队。这是统一获得锁的入口。

  • _EntryList 是一个双向链表,当 _cxq 队列不为空时,owener 会在 unlock 时根据不同的策略(QMode),将 _cxq 中的数据移动到 _entryList 中,获取 _entryList 列表头部的第一个线程通过
    ObjectMonitor::ExitEpilog 方法唤醒该节点封装的线程,唤醒操作最终由 unpark 完成。

QMode 策略官方解释:

1
2
3
4
5
6
7
8
9
10
11
12
//   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.

ObjectWaiter 对象

我们之前说过,在 _cxq 队列中竞争 Monitor 锁的线程会被封装成 ObjectWaiter 对象,存入 EntryList 等待队列中。下面是 ObjectWaiter 对象的构成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class ObjectWaiter : public StackObj {
public:
enum TStates { TS_UNDEF, TS_READY, TS_RUN, TS_WAIT, TS_ENTER, TS_CXQ } ;
enum Sorted { PREPEND, APPEND, SORTED } ;
ObjectWaiter * volatile _next; // 指向后一个 ObjectWaiter 对象
ObjectWaiter * volatile _prev; // 指向前一个
Thread* _thread; // 当前线程
jlong _notifier_tid;
ParkEvent * _event;
volatile int _notified ;
volatile TStates TState ;
Sorted _Sorted ; // List placement disposition
bool _active ; // Contention monitoring is enabled
};

由此我们可见,ObjectWaiter 对象是双向链表结构,保存了_thread(当前线程)以及当前的状态 TStates 等数据, 每个等待锁的线程都会被封装成 ObjectWaiter 对象。

下面我们介绍 ObjectWaiter 对象的几个核心方法:

TryLock(Thread* self)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int ObjectMonitor::TryLock (Thread * Self) {
for (;;) {
void * own = _owner ;

// 如果已经有人得到锁了, 直接返回
if (own != NULL) return 0 ;

// 获得锁成功
if (Atomic::cmpxchg_ptr (Self, &_owner, NULL) == NULL) {

// 要么保证 _recursions == 0, 要么设置 _recursions = 0。
assert (_recursions == 0, "invariant") ;
assert (_owner == Self, "invariant") ;
return 1 ;
}
// 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 ;
}
}

通过上面的源码我们可以分析出 TryLock() 方法的逻辑:

  • 首先判断当前 Monitor 对象是否有线程拥有 (own),即 owner == NULL
    • 如果非空,说明已经有线程拥有了该 Monitor 对象,则直接返回 0,结束;
    • 如果为空,则当前线程尝试将 _owner 设置成为自己 (Self),若成功直接返回 1,结束。

我们可以看出,对于锁的尝试获得只执行了一次,并不会多次尝试。

try_enter(Thread* THREAD)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
bool ObjectMonitor::try_enter(Thread* THREAD) {

// 判断当前线程是不是已经拥有了该 Monitor
if (THREAD != _owner) {

// 若不是,则设置当前线程为 Monitor 的拥有者
if (THREAD->is_lock_owned ((address)_owner)) {
assert(_recursions == 0, "internal state error");
_owner = THREAD ;
_recursions = 1 ;
OwnerIsThread = 1 ;
return true;
}

// 检查是否成功获得锁,若失败,返回false
if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
return false;
}
return true;

} else {

// 若线程已经拥有了该 Monitor,锁重入,计数 +1
_recursions++;
return true;
}
}
  • 通过上述逻辑我们可以看到:当前的线程是否已经持有了这个 Monitor 锁?
    • 如果持有,说明锁重入了,直接返回;
    • 如果没有,则尝试持有(设置当前线程为 Monitor 的拥有者,在检查设置是否成功了,无论成功与否都会返回)。

我们可以看出,整个过程是只做一次尝试,不论成功失败都只执行一次。与之前的 TryLock() 的区别在于

  • TryLock() 是该 Monitor 对象没有 _owner 时尝试获得锁;
  • try_enter() 是该 Monitor 对象已经有线程获得了,此时再次尝试获得锁。

enter(TRAPS)

enter()方法是整个获取到锁逻辑的核心实现,核心的思想是在整个链路中尽一切可能的获取到锁,如果实在获取不到情况进入等待队列进行等待。整体思路如下:

  1. 尝试获取获取获取锁,获取到成功直接返回。这个时刻整个等待成不是最低的;
  2. 判断自己是否已经拿到锁了,如果前面当前线程已经获取到锁了,也就直接返回。从这这里看ObjectMonitor 是可以重入的;
  3. 通过自旋多次尝试获取到锁的信息,如果获取到直接返回。满满的求生生欲望,避免自己加入到等待;
  4. 通过自旋转调用 EnterI 方法让自己加入到 _cxq 等待队列。一旦调用成功了整个线程就 park() 了,交出了执行状态等待唤醒了;
  5. 整个获取到锁之后就调用 exit()退出了。

ATTR ObjectMonitor::enter(TRAPS) 方法的主要源码如下(删减了一些用于断言的 assert 语句和对于整体运行框架联系不是十分紧密的代码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
void ATTR ObjectMonitor::enter(TRAPS) {
// 定义当前线程变量
Thread * const Self = THREAD ;
void * cur ;

// 1. 如果没有线程持有这个 Monitor,则将当前线程设置为持有者
cur = Atomic::cmpxchg_ptr (Self, &_owner, NULL) ;
if (cur == NULL) {
return ;
}

// 2.1 如果当前线程已经持有,则锁重入,_recursions+1
if (cur == Self) {
_recursions ++ ;
return ;
}

// 2.2 判断当前线程是否是 Monitor 的持有者
if (Self->is_lock_owned ((address)cur)) {
_recursions = 1 ;
_owner = Self ;
OwnerIsThread = 1 ;
return ;
}

Self->_Stalled = intptr_t(this) ;

// 3.1 如果允许自旋,那么通过自旋来获取锁的信息
if (Knob_SpinEarly && TrySpin (Self) > 0) {
assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
Self->_Stalled = 0 ;
return ;
}

// 3.2 如果前面的尝试都失败了,那么就开始正式进入等待队列 EntrtList 了
JavaThread * jt = (JavaThread *) Self ;

// 3.3 增加等待的线程计数 _count+1
Atomic::inc_ptr(&_count);
{
// 4.1 自旋进入到等待队列中
for (;;) {
jt->set_suspend_equivalent();

// 4.2 【重点】加入到等待队列
EnterI (THREAD) ;
if (!ExitSuspendEquivalent(jt)) break ;
_recursions = 0 ;
_succ = NULL ;

// 5.1 退出机制
exit (false, Self) ;
jt->java_suspend_self();
}
Self->set_current_pending_monitor(NULL);
}

// 5.2 减少等待计数 _count-1
Atomic::dec_ptr(&_count);
assert (_count >= 0, "invariant") ;
Self->_Stalled = 0 ;
}

EnterI(TRAPS)

EnterI 是整个进入等待队列的核心实现,核心的思想是在尽最后可能的获取到锁,如果实在不行加入到 _cxq 的等待队列,加入队列成功后将当前线程挂起

整体思路如下:

  1. 尝试通过 TryLock() 尝试获取下锁对象。
  2. 尝试通过自旋锁 TrySpin() 来获取锁的信息,这也是最后一次尝试了。实在不行就只能等待了。
  3. 构造等待节点对象,开始进行等待。
  4. 将当前线程的等待对象加入到能对队列. _cxq 排队队列中来
  5. 每个执行的循环周期都会经历尝试获取锁,获取不到将自己挂起 park() 的过程。中间有个小插曲尝试将自己设置成整个对象的维护线程(_Responsiblew),是防止获取锁的所有线程都进入了等待队列,没有人能通知其他线程进行拿锁的操作。

ATTR ObjectMonitor::EnterI(TRAPS) 方法的主要源码如下(删减了一些用于断言的 assert 语句和对于整体运行框架联系不是十分紧密的代码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
void ATTR ObjectMonitor::EnterI (TRAPS) {
Thread * Self = THREAD ;
// 1 尝试获取当前的锁对象
if (TryLock (Self) > 0) {
return ;
}
DeferredInitialize () ;
// 2 尝试通过自旋获取到锁的信息
if (TrySpin (Self) > 0) {
return ;
}
// 3 构造一个 ObjectWaiter对象 也就是等待对象
ObjectWaiter node(Self) ;
Self->_ParkEvent->reset() ;
node._prev = (ObjectWaiter *) 0xBAD ;
node.TState = ObjectWaiter::TS_CXQ ;

// 4.1 加入到能对队列_cxq中来
ObjectWaiter * nxt ;
for (;;) {
node._next = nxt = _cxq ;
// 4.2 添加完成直接返回
if (Atomic::cmpxchg_ptr (&node, &_cxq, nxt) == nxt) break ;
// 4.3 顺便捎带加入下锁 看看是否成功
if (TryLock (Self) > 0) {
return ;
}
}

// 4.4 如果没有其他线程 将当前线程设置成负责线程 以方便后面对象回收
if ((SyncFlags & 16) == 0 && nxt == NULL && _EntryList == NULL) {
Atomic::cmpxchg_ptr (Self, &_Responsible, NULL) ;
}

int nWakeups = 0 ;
int RecheckInterval = 1 ;
// 5.1 循环进入等待和唤醒的情况,这个代码需要仔细研读
for (;;) {
// 5.2 尝试加个锁看看是否有运气
if (TryLock (Self) > 0) break ;
if ((SyncFlags & 2) && _Responsible == NULL) {
Atomic::cmpxchg_ptr (Self, &_Responsible, NULL) ;
}
// 5.3 防止所有的线程都进入死等的情况,这样就会出现线程死锁
if (_Responsible == Self || (SyncFlags & 1)) {
// 5.4 过一段时间就起来看看
Self->_ParkEvent->park ((jlong) RecheckInterval) ;
RecheckInterval *= 8 ;
if (RecheckInterval > 1000) RecheckInterval = 1000 ;
} else {
Self->_ParkEvent->park() ;
}
// 5.5 尝试加个锁看看是否有运气
if (TryLock(Self) > 0) break ;
++ nWakeups ;
// 5.6 自旋试下 是否成功
if ((Knob_SpinAfterFutile & 1) && TrySpin (Self) > 0) break ;
if ((Knob_ResetEvent & 1) && Self->_ParkEvent->fired()) {
Self->_ParkEvent->reset() ;
OrderAccess::fence() ;
}
if (_succ == Self) _succ = NULL ;
}
// 6 已经获取到了锁,讲当前节点从等待队列中解除
UnlinkAfterAcquire (Self, &node) ;
return ;
}

exit(bool not_suspended, TRAPS)

线程执行同步方法或代码块结束之后,会调用 exit() 方法将当前线程从锁对象中移除,并尝试唤醒启动的线程来获取锁的过程。核心要点有两个,

  • 一个是将当前线程释放,这个很好理解就把 _owner 字段中线程值设为空就好了。
  • 另一个是唤醒其他线程,这个就涉及到相关的策略,因为前面他有一个排队队列 _cxq,还有一个 _EntryList,到底从哪里优先去取。提供了四种策略:
QMode 文字说明
QMode == 1 先反转 _cxq 队列,再唤醒栈顶(原栈底)元素唤醒,忽略 _EntryList 中的数据
QMode == 2 优先从 _cxq 栈顶唤醒,忽略 _EntryList 中的数据
QMode == 3 _cxq 中的数据加入到 _EntryList【尾部】中来 然后从 _EntryList 开始获取
QMode == 4 _cxq 中的数据加入到_EntryList【首部】来 然后从 _EntryList 开始获取

ATTR ObjectMonitor::exit(bool not_suspended, TRAPS) 方法的主要源码如下(删减了一些用于断言的 assert 语句和对于整体运行框架联系不是十分紧密的代码):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
void ATTR ObjectMonitor::exit(bool not_suspended, TRAPS) {
Thread * Self = THREAD ;
//1判断当前线程是否是锁的线程
if (THREAD != _owner) {
if (THREAD->is_lock_owned((address) _owner)) {
_owner = THREAD ;
_recursions = 0 ;
OwnerIsThread = 1 ;
}
}
//重入锁的次数减1
if (_recursions != 0) {
_recursions--; // this is simple recursive enter
return ;
}

// Invariant: after setting Responsible=null an thread must execute
// a MEMBAR or other serializing instruction before fetching EntryList|cxq.
if ((SyncFlags & 4) == 0) {
_Responsible = NULL ;
}
for (;;) {
if (Knob_ExitPolicy == 0) {
OrderAccess::release_store_ptr (&_owner, NULL) ; // drop the lock
OrderAccess::storeload() ;
//没有人需要获取锁了直接返回
if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
return ;
}
//当锁已经被其他线程抢占了 直接推出就好了
if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
return ;
}
} else {
if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
OrderAccess::release_store_ptr (&_owner, NULL) ; // drop the lock
OrderAccess::storeload() ;
if (_cxq == NULL || _succ != NULL) {
return ;
}
if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
return ;
}
}
}

ObjectWaiter * w = NULL ;
int QMode = Knob_QMode ;

//当QMode=2的时候 优先从_cxq唤醒
if (QMode == 2 && _cxq != NULL) {
w = _cxq ;
assert (w != NULL, "invariant") ;
assert (w->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
ExitEpilog (Self, w) ;
return ;
}
//当QMode=3的时候 讲_cxq中的数据加入到_EntryList尾部中来 然后从_EntryList开始获取
if (QMode == 3 && _cxq != NULL) {
w = _cxq ;
for (;;) {
ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ;
if (u == w) break ;
w = u ;
}
assert (w != NULL , "invariant") ;

ObjectWaiter * q = NULL ;
ObjectWaiter * p ;
for (p = w ; p != NULL ; p = p->_next) {
guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
p->TState = ObjectWaiter::TS_ENTER ;
p->_prev = q ;
q = p ;
}

//讲_cxq数据加入到_EntryList的队列中来
ObjectWaiter * Tail ;
for (Tail = _EntryList ; Tail != NULL && Tail->_next != NULL ; Tail = Tail->_next) ;
if (Tail == NULL) {
_EntryList = w ;
} else {
Tail->_next = w ;
w->_prev = Tail ;
}
}
//当QMode=4的时候 讲_cxq中的数据加入到_EntryList前面来 然后从_EntryList开始获取
if (QMode == 4 && _cxq != NULL) {
w = _cxq ;
for (;;) {
assert (w != NULL, "Invariant") ;
ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ;
if (u == w) break ;
w = u ;
}

//批量修改状态标志改成TS_ENTER
ObjectWaiter * q = NULL ;
ObjectWaiter * p ;
for (p = w ; p != NULL ; p = p->_next) {
p->TState = ObjectWaiter::TS_ENTER ;
p->_prev = q ;
q = p ;
}

//插到原有的_EntryList前面 从员_EntryList中获取
if (_EntryList != NULL) {
q->_next = _EntryList ;
_EntryList->_prev = q ;
}
_EntryList = w ;

// Fall thru into code that tries to wake a successor from EntryList
}

w = _EntryList ;
if (w != NULL) {
assert (w->TState == ObjectWaiter::TS_ENTER, "invariant") ;
ExitEpilog (Self, w) ;
return ;
}

// If we find that both _cxq and EntryList are null then just
// re-run the exit protocol from the top.
w = _cxq ;
if (w == NULL) continue ;

//默认的策略
for (;;) {
assert (w != NULL, "Invariant") ;
ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ;
if (u == w) break ;
w = u ;
}
//将cxq排队队列进行翻转。
if (QMode == 1) {
// QMode == 1 : drain cxq to EntryList, reversing order
// We also reverse the order of the list.
ObjectWaiter * s = NULL ;
ObjectWaiter * t = w ;
ObjectWaiter * u = NULL ;
while (t != NULL) {
guarantee (t->TState == ObjectWaiter::TS_CXQ, "invariant") ;
t->TState = ObjectWaiter::TS_ENTER ;
u = t->_next ;
t->_prev = u ;
t->_next = s ;
s = t;
t = u ;
}
_EntryList = s ;
assert (s != NULL, "invariant") ;
} else {
// QMode == 0 or QMode == 2
_EntryList = w ;
ObjectWaiter * q = NULL ;
ObjectWaiter * p ;
for (p = w ; p != NULL ; p = p->_next) {
guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
p->TState = ObjectWaiter::TS_ENTER ;
p->_prev = q ;
q = p ;
}
}
if (_succ != NULL) continue;

w = _EntryList ;
if (w != NULL) {
guarantee (w->TState == ObjectWaiter::TS_ENTER, "invariant") ;
ExitEpilog (Self, w) ;
return ;
}
}
}

附录

enter()EnterI()exit() 流程图示

objectmonitor_1