
- Owner线程发现条件不满足,调用wait方法,即可进入WaitSet编程WAITING状态;
- BLOCKED和WAITING的线程都处于阻塞状态,不占用CPU时间片;
- BLOCKED线程会在Owner线程释放锁时唤醒;
- WAITING线程会在Owner线程调用notify或notifyAll时唤醒,但唤醒后并不意味着立刻获得锁,仍需进入EntryList重新竞争;
C++原理
void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
// 创建线程
Thread * const Self = THREAD ;
// ...
// 将线程放进node双向链表中
ObjectWaiter node(Self);
// 等待队列状态
node.TState = ObjectWaiter::TS_WAIT ;
Self->_ParkEvent->reset() ;
// 中断标记
OrderAccess::fence();
// ...
// 加入队列
AddWaiter (&node) ;
// 下面就是一些运行后方法,改变node的状态
intptr_t save = _recursions; // record the old recursion count
_waiters++; // 等待队列加值
_recursions = 0; // 设置重入锁
exit (true, Self) ; // 退出monitor
guarantee (_owner != Self, "invariant") ;
// 线程状态
ObjectWaiter::TStates v = node.TState ;
// 线程状态为运行态
if (v == ObjectWaiter::TS_RUN) {
enter (Self) ;
} else {
guarantee (v == ObjectWaiter::TS_ENTER || v == ObjectWaiter::TS_CXQ, "invariant") ;
ReenterI (Self, &node) ;
node.wait_reenter_end(this);
}
}
inline void ObjectMonitor::AddWaiter(ObjectWaiter* node) {
assert(node != NULL, "should not dequeue NULL node");
assert(node->_prev == NULL, "node already in list");
assert(node->_next == NULL, "node already in list");
// 将节点放在队列末尾(循环双向链表)
if (_WaitSet == NULL) {
_WaitSet = node;
node->_prev = node;
node->_next = node;
} else {
ObjectWaiter* head = _WaitSet ;
ObjectWaiter* tail = head->_prev;
assert(tail->_next == head, "invariant check");
tail->_next = node;
head->_prev = node;
node->_next = head;
node->_prev = tail;
}
}
//线程释放调用exit方法
void ATTR ObjectMonitor::exit(bool not_suspended, TRAPS) {
// 创建线程
Thread * Self = THREAD ;
// 线程不是所属者
if (THREAD != _owner) {
// 执行检查锁拥有者
if (THREAD->is_lock_owned((address) _owner)) {
// 将该线程设置给拥有者
_owner = THREAD ;
// 设置重入锁
_recursions = 0 ;
// 拥有者标记
OwnerIsThread = 1 ;
} else {
// 抛出异常
...
}
//_recursions计数不等于0;说明还没出代码块;进入减减操作,
if (_recursions != 0) {
_recursions--; // this is simple recursive enter
TEVENT (Inflated exit - recursive) ;
return ;
}
if ((SyncFlags & 4) == 0) {
_Responsible = NULL ;
}
...
// 计数为0;开始唤醒cq竞争队列、enteryList阻塞队列
ObjectWaiter * w = NULL ;//w就是被唤醒的线程
// qmode = 2:直接绕过EntryList阻塞队列,从cxq(竞争)队列中获取线程用于竞争锁
if (QMode == 2 && _cxq != NULL) {
w = _cxq ;
ExitEpilog (Self, w) ;
return ;
}
// qmode =3:从cxq(竞争)队列插入EntryList(阻塞)尾部;
if (QMode == 3 && _cxq != NULL) {
...
}
// qmode =4:从cxq队列插入到_EntryList头部
if (QMode == 4 && _cxq != NULL) {
...
}
}
//唤醒线程
void ObjectMonitor::ExitEpilog (Thread * Self, ObjectWaiter * Wakee) {
ParkEvent * Trigger = Wakee->_event ;
// 唤醒之前被park()挂起的线程.
Trigger->unpark() ;// invoke ObjectMonitor::EnterI 方法,继续竞争
if (ObjectMonitor::_sync_Parks != NULL) {
ObjectMonitor::_sync_Parks->inc() ;
}
}
// 如果锁是空(cxq == null && succ == null)
// 并且在系统中并不是立即把线程从WaitSet移到EntryList
// 我们只是会唤醒一些线程,通过unpark()做到
void ObjectMonitor::notify(TRAPS) {
// 任务调度器
int Policy = Knob_MoveNotifyee ;
}