Java OpenResty Spring Spring Boot MySQL Redis MongoDB PostgreSQL Linux Android Nginx 面试 小程序 Arthas JVM AQS juc Kubernetes Docker DevOps


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

Java juc 大约 2764 字

原因

因为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

阅读 1168 · 发布于 2021-09-02

————        END        ————

Give me a Star, Thanks:)

https://github.com/fendoudebb

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

扫描二维码关注我
昵称:
随便看看 换一批