深入JVM源码篇-2-探索同步器

目录

1. 目标

2. 关键类

3. 数据模型说明

3.1. markWord

3.2. ObjectWaiter

3.3. ObjectMonitor

3.4. ObjectSynchronizer

4. 关键行为

4.1. ObjectSynchronizer#enter

4.2. ObjectMonitor#enter

4.3. ObjectMonitor::EnterI

5. 总结


1. 目标

我探索同步器的JVM源码,采取的步骤为:先找到同步器类,然后从数据模型入手,了解涉及到的关键模型,接着重点看关键行为的逻辑。

希望达到的目标:了解同步器的JVM实现,何为偏向、轻量级、重量级。

2. 关键类

markWord

ObjectWaiter

ObjectMonitor

ObjectSynchronizer

3. 数据模型说明

3.1. markWord

​​​描述了一个object的header,与偏向锁有关。依据markword来判断是否偏向锁和轻量级锁。

//  markWord 描述了一个object的header。header分为32位或64位。依据markword来判断是否偏向锁和轻量级锁。
//  偏向锁模式 表示锁偏向一个给定线程或匿名偏向。
//  若偏向一个给定线程,则该线程可不通过原子操作即可加锁或释放锁。
//  低3位用于配置偏向模式。
//    [JavaThread* | epoch | age | 1 | 01]       lock is biased toward given thread
//    [0           | epoch | age | 1 | 01]       lock is anonymously biased
//  低2位可描述3中情况:已加锁、已释放锁、监视器
//    [ptr             | 00]  locked             ptr points to real header on stack
//    [header      | 0 | 01]  unlocked           regular object header
//    [ptr             | 10]  monitor            inflated lock (header is wapped out)
//    [ptr             | 11]  marked             used to mark an object
//    [0 ............ 0| 00]  inflating          inflation in progress

class markWord {
 private:
  uintptr_t _value;
 .....
}

3.2. ObjectWaiter

代表 争抢监视器的线程,一个线程对应一个ObjectWaiter,定义一个双向链表。

// ObjectWaiter 代表 争抢监视器的线程,一个线程对应一个ObjectWaiter
class ObjectWaiter : public StackObj {
 public:
  enum TStates { TS_UNDEF, TS_READY, TS_RUN, TS_WAIT, TS_ENTER, TS_CXQ };
  // ObjectWaiter 双向链表
  ObjectWaiter* volatile _next;
  ObjectWaiter* volatile _prev;
  // 关联的线程
  Thread*       _thread;
  jlong         _notifier_tid;
  ParkEvent *   _event;
  // 是否已被notify
  volatile int  _notified;
  // 状态
  volatile TStates TState;
  // 是否可以去争抢监视器
  bool          _active;           // Contention monitoring is enabled
 public:
  ObjectWaiter(Thread* thread);

  // 决定notify ObjectWaiter后,并通过该接口,让其重新争抢监视器
  void wait_reenter_begin(ObjectMonitor *mon);
  void wait_reenter_end(ObjectMonitor *mon);
};

3.3. ObjectMonitor

代表对象的监视器,实现重量级\轻量级锁版本。

关键field有markWord类型的_header、 占用者owner、ObjectWaiter的链表_EntryList、ObjectWaiter的链表waitSet。

// ObjectMonitor 实现了JavaMonitor的重量级版本。由于Object.wait()的使用或争抢,扩充了轻量级锁版本。
class ObjectMonitor : public CHeapObj<mtInternal> {
  ...

  // The sync code expects the header field to be at offset zero (0).
  // Enforced by the assert() in header_addr().
  volatile markWord _header;        // displaced object header word - mark
  // 监视器 关联的 对象
  WeakHandle _object;               // backward object pointer
  ...
  // 当前占用监视器的线程
  void* _owner;                     // pointer to owning thread OR BasicLock
  // 之前占用监视器的线程ID
  volatile jlong _previous_owner_tid;  // thread id of the previous owner of the monitor

  // ObjectMonitor 单向链
  ObjectMonitor* _next_om;          // Next ObjectMonitor* linkage
  // 重入数,0表示第一次获取监视器
  volatile intx _recursions;        // recursion count, 0 for first entry
  // 由获取监视器而阻塞的线程构成的链表
  ObjectWaiter* volatile _EntryList;  // Threads blocked on entry or reentry.
                                      // The list is actually composed of WaitNodes,
                                      // acting as proxies for Threads.
  // 由于获取监视器而阻塞的近期线程构成的链表
  ObjectWaiter* volatile _cxq;      // LL of recently-arrived threads blocked on entry.
  Thread* volatile _succ;           // Heir presumptive thread - used for futile wakeup throttling
  Thread* volatile _Responsible;
  // 正在争抢监视器的线程个数
  jint  _contentions;               // Number of active contentions in enter(). It is used by is_busy()
                                    // along with other fields to determine if an ObjectMonitor can be
                                    // deflated. It is also used by the async deflation protocol. See
                                    // ObjectMonitor::deflate_monitor().
 protected:
    // 调用监视器wait()且没有被notify的线程构成的链表
  ObjectWaiter* volatile _WaitSet;  // LL of threads wait()ing on the monitor
  // 调用监视器wait()且没有被notify的线程数量
  volatile jint  _waiters;          // number of waiting threads
 private:
    // 用于保护waitset,操作waitset前后需要使用自旋锁来加锁和释放锁
  volatile int _WaitSetLock;        // protects Wait Queue - simple spinlock
....
}

3.4. ObjectSynchronizer

对象同步器

// 对象同步器,定义行为enter、exit、wait、notify、notifyall、reenter、inflate(从轻量级膨胀为重量级)
class ObjectSynchronizer{
...
}

4. 关键行为

4.1. ObjectSynchronizer#enter

概述为:判断是否采取轻量级,否则重量级。

可以看到,通过markword判断是否使用轻量级版本,且轻量级版本只是尝试一次cas设置监视器的header域。

void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, TRAPS) {
  ...

  markWord mark = obj->mark();
  // 不允许使用偏向锁
  assert(!mark.has_bias_pattern(), "should not see bias pattern here");

  // 轻量级版本 BasicLock
  // last bits = 001  参见markword的注释: [header      | 0 | 01]  unlocked           regular object header
  if (mark.is_neutral()) {
    // unlocked情况,直接cas改变lock的mark,成功则表示获取监视器成功
    // Anticipate successful CAS -- the ST of the displaced mark must
    // be visible <= the ST performed by the CAS.
    lock->set_displaced_header(mark);
    if (mark == obj()->cas_set_mark(markWord::from_pointer(lock), mark)) {
      return;
    }
    // 失败则使用重量级版本 Fall through to inflate() ...
  } else if (mark.has_locker() &&
             THREAD->is_lock_owned((address)mark.locker())) {
      // mark 为 locked,参见markword:[ptr             | 00]  locked             ptr points to real header on stack
      // 且owner是当前线程
    ...
    lock->set_displaced_header(markWord::from_pointer(NULL));
    return;
  }

  // The object header will never be displaced to this lock,
  // so it does not matter what the value is, except that it
  // must be non-zero to avoid looking like a re-entrant lock,
  // and must not look locked either.
  lock->set_displaced_header(markWord::unused_mark());
  // An async deflation can race after the inflate() call and before
  // enter() can make the ObjectMonitor busy. enter() returns false if
  // we have lost the race to async deflation and we simply try again.
  // 重量级版本
  while (true) {
    ObjectMonitor* monitor = inflate(THREAD, obj(), inflate_cause_monitor_enter);
    if (monitor->enter(THREAD)) {
      return;
    }
  }
}

4.2. ObjectMonitor#enter

按照ObjectSynchronizer::enter的注释,轻量级逻辑失败将膨胀为重量级锁,所以ObjectMonitor::enter就是重量级锁。

大致步骤:首先若占用者的owner为null则直接占用成功,其次若重入则占用成功,最后争抢。

轻量级版本是判断和设置markword,与此对比,重量级版本是判断和设置owner。

从代码可看出,所谓重量级版本,就是自旋方式获取监视器。JDK的AQS也是自旋方式,因此我的看法是AQS就是重量级。

// Enter support
// 重量级版本
bool ObjectMonitor::enter(TRAPS) {
  // The following code is ordered to check the most common cases first
  // and to reduce RTS->RTO cache line upgrades on SPARC and IA32 processors.
  Thread * const Self = THREAD;

  void* cur = try_set_owner_from(NULL, Self);
  // 当前监视器没有被占用的情况,直接占用成功
  if (cur == NULL) {
    assert(_recursions == 0, "invariant");
    return true;
  }

  // 之前的占用者就是当前线程,则重入成功
  if (cur == Self) {
    // TODO-FIXME: check for integer overflow!  BUGID 6557169.
    _recursions++;
    return true;
  }
  // 之前的占用者就是当前线程,则重入成功
  if (Self->is_lock_owned((address)cur)) {
    assert(_recursions == 0, "internal state error");
    _recursions = 1;
    set_owner_from_BasicLock(cur, Self);  // Convert from BasicLock* to Thread*.
    return true;
  }

  // We've encountered genuine contention.
  assert(Self->_Stalled == 0, "invariant");
  Self->_Stalled = intptr_t(this);


  // 尝试自旋加锁,自旋有限次数
  if (TrySpin(Self) > 0) {
    assert(...);
    Self->_Stalled = 0;
    return true;
  }

  assert(...);
  JavaThread * jt = Self->as_Java_thread();
  assert(jt->thread_state() != _thread_blocked, "invariant");

...

  { // Change java thread status to indicate blocked on monitor enter.
    ...
    for (;;) {
      jt->set_suspend_equivalent();
      // cleared by handle_special_suspend_equivalent_condition()
      // or java_suspend_self()

      EnterI(THREAD);

      // 已经获取监视器锁,但是要求该线程没有被要求挂起
      if (!ExitSuspendEquivalent(jt)) break;
      // 到这一步,表示已经获得监视器锁,但是需要等待'挂起当前线程'的其他线程A。为了符合逻辑,所以线程不可以在处于挂起时进入监视器。
      _recursions = 0;
      _succ = NULL;
      exit(false, Self);
      // 因为被请求挂起,所以执行挂起操作。
      jt->java_suspend_self();
    }
    Self->set_current_pending_monitor(NULL);

    ...
  }

  add_to_contentions(-1);
  assert(contentions() >= 0, "must not be negative: contentions=%d", contentions());
  Self->_Stalled = 0;

  ...
  return true;
}

4.3. ObjectMonitor::EnterI

获取监视器锁,主要通过自旋方式。

void ObjectMonitor::EnterI(TRAPS) {
  Thread * const Self = THREAD;
  assert(Self->as_Java_thread()->thread_state() == _thread_blocked, "invariant");

  // 尝试一次,使用cas尝试这是owner
  if (TryLock (Self) > 0) {
    assert(...);
    return;
  }

  ...

  // 尝试有限次数的自旋
  if (TrySpin(Self) > 0) {
    assert(...);
    return;
  }

  ...

  // 将当前线程放到‘_cxq近期争抢者链表’的头部
  ObjectWaiter * nxt;
  for (;;) {
    node._next = nxt = _cxq;
    // 插入成功则退出循环
    if (Atomic::cmpxchg(&_cxq, nxt, &node) == nxt) break;

    // 尝试一次,使用cas尝试这是owner
    if (TryLock (Self) > 0) {
      assert(...);
      return;
    }
  }

  ...

  int nWakeups = 0;
  int recheckInterval = 1;

  // 自旋 park 尝试获取监视器
  for (;;) {
    // 尝试一次,使用cas尝试这是owner  
    if (TryLock(Self) > 0) break;
    assert(owner_raw() != Self, "invariant");

    // park self
    if (_Responsible == Self) {
      Self->_ParkEvent->park((jlong) recheckInterval);
      // Increase the recheckInterval, but clamp the value.
      recheckInterval *= 8;
      if (recheckInterval > MAX_RECHECK_INTERVAL) {
        recheckInterval = MAX_RECHECK_INTERVAL;
      }
    } else {
      Self->_ParkEvent->park();
    }
    // 尝试一次,使用cas尝试这是owner  
    if (TryLock(Self) > 0) break;

    ...
  }

  // 到此,表示已经获取监视器锁
  ...
  return;
}

5. 总结

从实现原理角度,对比ObjectSynchronizer与AQS,除了ObjectSynchronizer的轻量级版本,两者都使用到链表、自旋、park、cas,个人认为没有特别的差异。