ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS)

2019-11-10 15:58:07  阅读:201  来源: 互联网

标签:node TRAPS thread Self millis TS interruptible wait monitor


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

 

标签:node,TRAPS,thread,Self,millis,TS,interruptible,wait,monitor
来源: https://www.cnblogs.com/xiaofan156/p/11810632.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有