
- 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 ;}