Java 使用 wait 等待会使 synchronized 升级为重量级锁

Java juc About 2,764 words

原因

因为wait方法会让锁对象从owner拥有者变为waitSet队列中等待。

所以必须关联一个Monitor对象,这样synchronized就升级为了重量级锁。

底层 C++ 代码

主要为ObjectMonitor相关代码

class ObjectWaiter : public StackObj {
 public:
  enum TStates { TS_UNDEF, TS_READY, TS_RUN, TS_WAIT, TS_ENTER, TS_CXQ } ;
  enum Sorted  { PREPEND, APPEND, SORTED } ;
  ObjectWaiter * volatile _next;
  ObjectWaiter * volatile _prev;
  Thread*       _thread;
  jlong         _notifier_tid;

};

class ObjectMonitor {
    // ...
  ObjectMonitor() {
    _owner        = NULL; // 锁持有者
    _WaitSet      = NULL; // 调用 wait 方法等待 notify 的列表
    _WaitSetLock  = 0 ;
    _EntryList    = NULL ; // 竞争锁的队列
    _previous_owner_tid = 0;
  }
};

wait方法添加到waitSet的双向链表中

// -----------------------------------------------------------------------------
// Wait/Notify/NotifyAll
//
// Note: a subset of changes to ObjectMonitor::wait()
// will need to be replicated in complete_exit above
void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
   // ...

   // create a node to be put into the queue
   // Critically, after we reset() the event but prior to park(), we must check
   // for a pending interrupt.
   ObjectWaiter node(Self); // 包装成 waitSet 入队对象
   node.TState = ObjectWaiter::TS_WAIT ;
   Self->_ParkEvent->reset() ;
   OrderAccess::fence();          // ST into Event; membar ; LD interrupted-flag

   // Enter the waiting queue, which is a circular doubly linked list in this case
   // but it could be a priority queue or any data structure.
   // _WaitSetLock protects the wait queue.  Normally the wait queue is accessed only
   // by the the owner of the monitor *except* in the case where park()
   // returns because of a timeout of interrupt.  Contention is exceptionally rare
   // so we use a simple spin-lock instead of a heavier-weight blocking lock.

   // 自旋锁代替重量级锁
   Thread::SpinAcquire (&_WaitSetLock, "WaitSet - add") ; // 线程自旋
   AddWaiter (&node) ; // waitSet 入队
   Thread::SpinRelease (&_WaitSetLock) ;
}

// 添加到 waitSet 双向链表中
inline void ObjectMonitor::AddWaiter(ObjectWaiter* node) {
  assert(node != NULL, "should not dequeue NULL node");
  assert(node->_prev == NULL, "node already in list");
  assert(node->_next == NULL, "node already in list");
  // put node at end of queue (circular doubly linked list)
  // 双向链表
  if (_WaitSet == NULL) {
    _WaitSet = node;
    node->_prev = node;
    node->_next = node;
  } else {
    ObjectWaiter* head = _WaitSet ;
    ObjectWaiter* tail = head->_prev;
    assert(tail->_next == head, "invariant check");
    tail->_next = node;
    head->_prev = node;
    node->_next = head;
    node->_prev = tail;
  }
}

OpenJDK 源码

http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/2bcd260edd04/src/share/vm/runtime/objectMonitor.cpp

Views: 2,684 · Posted: 2021-09-02

————        END        ————

Give me a Star, Thanks:)

https://github.com/fendoudebb/LiteNote

扫描下方二维码关注公众号和小程序↓↓↓

扫描下方二维码关注公众号和小程序↓↓↓


Today On History
Browsing Refresh