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. 当前线程挂起;