小凡156

博客园 首页 新随笔 联系 订阅 管理
  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. 当前线程挂起;

 

posted on 2019-11-10 15:43  小凡156  阅读(355)  评论(0编辑  收藏  举报