1 // Wait/Notify/NotifyAll 2 3 // 4 5 // Note: a subset of changes to ObjectMonitor::wait() 6 7 // will need to be replicated in complete_exit above 8 9 void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { 10 11 Thread * const Self = THREAD ; 12 13 assert(Self->is_Java_thread(), "Must be Java thread!"); 14 15 JavaThread *jt = (JavaThread *)THREAD; 16 17 18 DeferredInitialize () ; 19 20 21 // Throw IMSX or IEX. 22 23 CHECK_OWNER(); 24 25 26 EventJavaMonitorWait event; 27 28 29 // check for a pending interrupt 30 31 if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) { 32 33 // post monitor waited event. Note that this is past-tense, we are done waiting. 34 35 if (JvmtiExport::should_post_monitor_waited()) { 36 37 // Note: 'false' parameter is passed here because the 38 39 // wait was not timed out due to thread interrupt. 40 41 JvmtiExport::post_monitor_waited(jt, this, false); 42 43 44 // In this short circuit of the monitor wait protocol, the 45 46 // current thread never drops ownership of the monitor and 47 48 // never gets added to the wait queue so the current thread 49 50 // cannot be made the successor. This means that the 51 52 // JVMTI_EVENT_MONITOR_WAITED event handler cannot accidentally 53 54 // consume an unpark() meant for the ParkEvent associated with 55 56 // this ObjectMonitor. 57 58 } 59 60 if (event.should_commit()) { 61 62 post_monitor_wait_event(&event, 0, millis, false); 63 64 } 65 66 TEVENT (Wait - Throw IEX) ; 67 68 THROW(vmSymbols::java_lang_InterruptedException()); 69 70 return ; 71 72 } 73 74 75 TEVENT (Wait) ; 76 77 78 assert (Self->_Stalled == 0, "invariant") ; 79 80 Self->_Stalled = intptr_t(this) ; 81 82 jt->set_current_waiting_monitor(this); 83 84 85 // create a node to be put into the queue 86 87 // Critically, after we reset() the event but prior to park(), we must check 88 89 // for a pending interrupt. 90 将当前线程包装成ObjectWaiter对象,并且状态为TS_WAIT,这里对应的是jstack看到的线程状态WAITING 91 ObjectWaiter node(Self); 92 93 node.TState = ObjectWaiter::TS_WAIT ; 94 95 Self->_ParkEvent->reset() ; 96 97 OrderAccess::fence(); // ST into Event; membar ; LD interrupted-flag 98 99 100 // Enter the waiting queue, which is a circular doubly linked list in this case 101 102 // but it could be a priority queue or any data structure. 103 104 // _WaitSetLock protects the wait queue. Normally the wait queue is accessed only 105 106 // by the the owner of the monitor *except* in the case where park() 107 108 // returns because of a timeout of interrupt. Contention is exceptionally rare 109 110 // so we use a simple spin-lock instead of a heavier-weight blocking lock. 111 112 113 Thread::SpinAcquire (&_WaitSetLock, "WaitSet - add") ; 114 这个ObjectWaiter对象被放入了_WaitSet中,_WaitSet是个环形双向链表(circular doubly linked list) 115 AddWaiter (&node) ; 116 117 Thread::SpinRelease (&_WaitSetLock) ; 118 119 120 if ((SyncFlags & 4) == 0) { 121 122 _Responsible = NULL ; 123 124 } 125 126 intptr_t save = _recursions; // record the old recursion count 127 128 _waiters++; // increment the number of waiters 129 130 _recursions = 0; // set the recursion level to be 1 131 132 exit (true, Self) ; // exit the monitor 133 134 guarantee (_owner != Self, "invariant") ; 135 136 137 // The thread is on the WaitSet list - now park() it. 138 139 // On MP systems it's conceivable that a brief spin before we park 140 141 // could be profitable. 142 143 // 144 145 // TODO-FIXME: change the following logic to a loop of the form 146 147 // while (!timeout && !interrupted && _notified == 0) park() 148 149 150 int ret = OS_OK ; 151 152 int WasNotified = 0 ; 153 154 { // State transition wrappers 155 156 OSThread* osthread = Self->osthread(); 157 158 OSThreadWaitState osts(osthread, true); 159 160 { 161 162 ThreadBlockInVM tbivm(jt); 163 164 // Thread is in thread_blocked state and oop access is unsafe. 165 166 jt->set_suspend_equivalent(); 167 168 169 if (interruptible && (Thread::is_interrupted(THREAD, false) || HAS_PENDING_EXCEPTION)) { 170 171 // Intentionally empty 172 173 } else 174 175 if (node._notified == 0) { 176 177 if (millis <= 0) { 178 当前线程通过park()方法开始挂起(suspend) 179 Self->_ParkEvent->park () ; 180 181 } else { 182 183 ret = Self->_ParkEvent->park (millis) ; 184 185 } 186 187 } 188 189 190 // were we externally suspended while we were waiting? 191 192 if (ExitSuspendEquivalent (jt)) { 193 194 // TODO-FIXME: add -- if succ == Self then succ = null. 195 196 jt->java_suspend_self(); 197 198 } 199 200 201 } // Exit thread safepoint: transition _thread_blocked -> _thread_in_vm 202 203 204 205 // Node may be on the WaitSet, the EntryList (or cxq), or in transition 206 207 // from the WaitSet to the EntryList. 208 209 // See if we need to remove Node from the WaitSet. 210 211 // We use double-checked locking to avoid grabbing _WaitSetLock 212 213 // if the thread is not on the wait queue. 214 215 // 216 217 // Note that we don't need a fence before the fetch of TState. 218 219 // In the worst case we'll fetch a old-stale value of TS_WAIT previously 220 221 // written by the is thread. (perhaps the fetch might even be satisfied 222 223 // by a look-aside into the processor's own store buffer, although given 224 225 // the length of the code path between the prior ST and this load that's 226 227 // highly unlikely). If the following LD fetches a stale TS_WAIT value 228 229 // then we'll acquire the lock and then re-fetch a fresh TState value. 230 231 // That is, we fail toward safety. 232 233 234 if (node.TState == ObjectWaiter::TS_WAIT) { 235 236 Thread::SpinAcquire (&_WaitSetLock, "WaitSet - unlink") ; 237 238 if (node.TState == ObjectWaiter::TS_WAIT) { 239 240 DequeueSpecificWaiter (&node) ; // unlink from WaitSet 241 242 assert(node._notified == 0, "invariant"); 243 244 node.TState = ObjectWaiter::TS_RUN ; 245 246 } 247 248 Thread::SpinRelease (&_WaitSetLock) ; 249 250 } 251 252 253 // The thread is now either on off-list (TS_RUN), 254 255 // on the EntryList (TS_ENTER), or on the cxq (TS_CXQ). 256 257 // The Node's TState variable is stable from the perspective of this thread. 258 259 // No other threads will asynchronously modify TState. 260 261 guarantee (node.TState != ObjectWaiter::TS_WAIT, "invariant") ; 262 263 OrderAccess::loadload() ; 264 265 if (_succ == Self) _succ = NULL ; 266 267 WasNotified = node._notified ; 268 269 270 // Reentry phase -- reacquire the monitor. 271 272 // re-enter contended monitor after object.wait(). 273 274 // retain OBJECT_WAIT state until re-enter successfully completes 275 276 // Thread state is thread_in_vm and oop access is again safe, 277 278 // although the raw address of the object may have changed. 279 280 // (Don't cache naked oops over safepoints, of course). 281 282 283 // post monitor waited event. Note that this is past-tense, we are done waiting. 284 285 if (JvmtiExport::should_post_monitor_waited()) { 286 287 JvmtiExport::post_monitor_waited(jt, this, ret == OS_TIMEOUT); 288 289 290 if (node._notified != 0 && _succ == Self) { 291 292 // In this part of the monitor wait-notify-reenter protocol it 293 294 // is possible (and normal) for another thread to do a fastpath 295 296 // monitor enter-exit while this thread is still trying to get 297 298 // to the reenter portion of the protocol. 299 300 // 301 302 // The ObjectMonitor was notified and the current thread is 303 304 // the successor which also means that an unpark() has already 305 306 // been done. The JVMTI_EVENT_MONITOR_WAITED event handler can 307 308 // consume the unpark() that was done when the successor was 309 310 // set because the same ParkEvent is shared between Java 311 312 // monitors and JVM/TI RawMonitors (for now). 313 314 // 315 316 // We redo the unpark() to ensure forward progress, i.e., we 317 318 // don't want all pending threads hanging (parked) with none 319 320 // entering the unlocked monitor. 321 322 node._event->unpark(); 323 324 } 325 326 } 327 328 329 if (event.should_commit()) { 330 331 post_monitor_wait_event(&event, node._notifier_tid, millis, ret == OS_TIMEOUT); 332 333 } 334 335 336 OrderAccess::fence() ; 337 338 339 assert (Self->_Stalled != 0, "invariant") ; 340 341 Self->_Stalled = 0 ; 342 343 344 assert (_owner != Self, "invariant") ; 345 346 ObjectWaiter::TStates v = node.TState ; 347 348 if (v == ObjectWaiter::TS_RUN) { 349 350 enter (Self) ; 351 352 } else { 353 354 guarantee (v == ObjectWaiter::TS_ENTER || v == ObjectWaiter::TS_CXQ, "invariant") ; 355 356 ReenterI (Self, &node) ; 357 358 node.wait_reenter_end(this); 359 360 } 361 362 363 // Self has reacquired the lock. 364 365 // Lifecycle - the node representing Self must not appear on any queues. 366 367 // Node is about to go out-of-scope, but even if it were immortal we wouldn't 368 369 // want residual elements associated with this thread left on any lists. 370 371 guarantee (node.TState == ObjectWaiter::TS_RUN, "invariant") ; 372 373 assert (_owner == Self, "invariant") ; 374 375 assert (_succ != Self , "invariant") ; 376 377 } // OSThreadWaitState() 378 379 380 jt->set_current_waiting_monitor(NULL); 381 382 383 guarantee (_recursions == 0, "invariant") ; 384 385 _recursions = save; // restore the old recursion count 386 387 _waiters--; // decrement the number of waiters 388 389 390 // Verify a few postconditions 391 392 assert (_owner == Self , "invariant") ; 393 394 assert (_succ != Self , "invariant") ; 395 396 assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ; 397 398 399 if (SyncFlags & 32) { 400 401 OrderAccess::fence() ; 402 403 } 404 405 406 // check if the notification happened 407 408 if (!WasNotified) { 409 410 // no, it could be timeout or Thread.interrupt() or both 411 412 // check for interrupt event, otherwise it is timeout 413 414 if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) { 415 416 TEVENT (Wait - throw IEX from epilog) ; 417 418 THROW(vmSymbols::java_lang_InterruptedException()); 419 420 } 421 422 } 423 424 425 // NOTE: Spurious wake up will be consider as timeout. 426 427 // Monitor notify has precedence over thread interrupt. 428 429 }
ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS)
总结:wait()方法的内容
1. 把当前线程包装成ObjectWaiter对象,状态为TS_WAIT;
2. ObjectWaiter对象被放入_WaitSet中;
3. 当前线程挂起;