1 // Consider: 2 3 // If the lock is cool (cxq == null && succ == null) and we're on an MP system 4 5 // then instead of transferring a thread from the WaitSet to the EntryList 6 7 // we might just dequeue a thread from the WaitSet and directly unpark() it. 8 9 10 void ObjectMonitor::notify(TRAPS) { 11 12 CHECK_OWNER(); 13 14 if (_WaitSet == NULL) { 15 16 TEVENT (Empty-Notify) ; 17 18 return ; 19 20 } 21 22 DTRACE_MONITOR_PROBE(notify, this, object(), THREAD); 23 24 注意Policy的赋值 25 int Policy = Knob_MoveNotifyee ; 26 27 28 Thread::SpinAcquire (&_WaitSetLock, "WaitSet - notify") ; 29 调用DequeueWaiter()方法将_WaitSet队列的第一个值取出并返回 30 ObjectWaiter * iterator = DequeueWaiter() ; 31 32 if (iterator != NULL) { 33 34 TEVENT (Notify1 - Transfer) ; 35 36 guarantee (iterator->TState == ObjectWaiter::TS_WAIT, "invariant") ; 37 38 guarantee (iterator->_notified == 0, "invariant") ; 39 40 if (Policy != 4) { 41 42 iterator->TState = ObjectWaiter::TS_ENTER ; 43 44 } 45 46 iterator->_notified = 1 ; 47 48 Thread * Self = THREAD; 49 50 iterator->_notifier_tid = Self->osthread()->thread_id(); 51 52 53 ObjectWaiter * List = _EntryList ; 54 55 if (List != NULL) { 56 57 assert (List->_prev == NULL, "invariant") ; 58 59 assert (List->TState == ObjectWaiter::TS_ENTER, "invariant") ; 60 61 assert (List != iterator, "invariant") ; 62 63 } 64 65 Policy == 0:放入_EntryList队列的排头位置; 66 if (Policy == 0) { // prepend to EntryList 67 68 if (List == NULL) { 69 70 iterator->_next = iterator->_prev = NULL ; 71 72 _EntryList = iterator ; 73 74 } else { 75 76 List->_prev = iterator ; 77 78 iterator->_next = List ; 79 80 iterator->_prev = NULL ; 81 82 _EntryList = iterator ; 83 84 } 85 86 } else 87 Policy == 1:放入_EntryList队列的末尾位置; 88 if (Policy == 1) { // append to EntryList 89 90 if (List == NULL) { 91 92 iterator->_next = iterator->_prev = NULL ; 93 94 _EntryList = iterator ; 95 96 } else { 97 98 // CONSIDER: finding the tail currently requires a linear-time walk of 99 100 // the EntryList. We can make tail access constant-time by converting to 101 102 // a CDLL instead of using our current DLL. 103 104 ObjectWaiter * Tail ; 105 106 for (Tail = List ; Tail->_next != NULL ; Tail = Tail->_next) ; 107 108 assert (Tail != NULL && Tail->_next == NULL, "invariant") ; 109 110 Tail->_next = iterator ; 111 112 iterator->_prev = Tail ; 113 114 iterator->_next = NULL ; 115 116 } 117 118 } else 119 Policy == 2:_EntryList队列为空就放入_EntryList,否则放入_cxq队列的排头位置;
请注意把ObjectWaiter的地址写到_cxq变量的时候要用CAS操作,因为此时可能有其他线程正在竞争锁,竞争失败的时候会将自己包装成ObjectWaiter对象加入到_cxq中; 120 if (Policy == 2) { // prepend to cxq 121 122 // prepend to cxq 123 124 if (List == NULL) { 125 126 iterator->_next = iterator->_prev = NULL ; 127 128 _EntryList = iterator ; 129 130 } else { 131 132 iterator->TState = ObjectWaiter::TS_CXQ ; 133 134 for (;;) { 135 136 ObjectWaiter * Front = _cxq ; 137 138 iterator->_next = Front ; 139 140 if (Atomic::cmpxchg_ptr (iterator, &_cxq, Front) == Front) { 141 142 break ; 143 144 } 145 146 } 147 148 } 149 150 } else 151 Policy == 3:放入_cxq队列中,末尾位置; 152 if (Policy == 3) { // append to cxq 153 154 iterator->TState = ObjectWaiter::TS_CXQ ; 155 156 for (;;) { 157 158 ObjectWaiter * Tail ; 159 160 Tail = _cxq ; 161 162 if (Tail == NULL) { 163 164 iterator->_next = NULL ; 165 166 if (Atomic::cmpxchg_ptr (iterator, &_cxq, NULL) == NULL) { 167 168 break ; 169 170 } 171 172 } else { 173 174 while (Tail->_next != NULL) Tail = Tail->_next ; 175 176 Tail->_next = iterator ; 177 178 iterator->_prev = Tail ; 179 180 iterator->_next = NULL ; 181 182 break ; 183 184 } 185 186 } 187 188 } else { 189 Policy等于其他值,立即唤醒ObjectWaiter对应的线程; 190 ParkEvent * ev = iterator->_event ; 191 192 iterator->TState = ObjectWaiter::TS_RUN ; 193 194 OrderAccess::fence() ; 195 196 ev->unpark() ; 197 198 } 199 200 201 if (Policy < 4) { 202 203 iterator->wait_reenter_begin(this); 204 205 } 206 207 208 // _WaitSetLock protects the wait queue, not the EntryList. We could 209 210 // move the add-to-EntryList operation, above, outside the critical section 211 212 // protected by _WaitSetLock. In practice that's not useful. With the 213 214 // exception of wait() timeouts and interrupts the monitor owner 215 216 // is the only thread that grabs _WaitSetLock. There's almost no contention 217 218 // on _WaitSetLock so it's not profitable to reduce the length of the 219 220 // critical section. 221 222 } 223 224 225 Thread::SpinRelease (&_WaitSetLock) ; 226 227 228 if (iterator != NULL && ObjectMonitor::_sync_Notifications != NULL) { 229 230 ObjectMonitor::_sync_Notifications->inc() ; 231 232 } 233 234 }
对ObjectWaiter对象的处理方式,根据Policy的不同而不同:
Policy == 0:放入_EntryList队列的排头位置;
Policy == 1:放入_EntryList队列的末尾位置;
Policy == 2:_EntryList队列为空就放入_EntryList,否则放入_cxq队列的排头位置;
Policy == 3:放入_cxq队列中,末尾位置;更新_cxq变量的值的时候,同样要通过CAS注意并发问题;
Policy等于其他值,立即唤醒ObjectWaiter对应的线程;
总结执行notify时的内容:
1. 执行过wait的线程都 在队列_WaitSet中,此处从_WaitSet中取出第一个;
2. 根据Policy的不同,将这个线程放入_EnterList或者_cxq队列中的起始或末尾位置;