Java同步关键字synchronize底层实现原理(下)

monitor竞争

当锁膨胀完成并返回对应的monitor时,并不表示该线程竞争到了锁,真正的锁竞争发生在ObjectMonitor::enter方法中。

Java同步关键字synchronize底层实现原理(下)1、通过CAS尝试把monitor的_owner字段设置为当前线程;

2、如果设置之前的_owner指向当前线程,说明当前线程再次进入monitor,即重入锁,执行_recursions ++ ,记录重入的次数;

3、如果之前的_owner指向的地址在当前线程中,这种描述有点拗口,换一种说法:之前_owner指向的BasicLock在当前线程栈上,说明当前线程是第一次进入该monitor,设置_recursions为1,_owner为当前线程,该线程成功获得锁并返回;

4、如果获取锁失败,则等待锁的释放;

monitor等待

monitor竞争失败的线程,通过自旋执行ObjectMonitor::EnterI方法等待锁的释放,EnterI方法的部分逻辑实现如下:

Java同步关键字synchronize底层实现原理(下)

1、当前线程被封装成ObjectWaiter对象node,状态设置成ObjectWaiter::TS_CXQ;

2、在for循环中,通过CAS把node节点push到_cxq列表中,同一时刻可能有多个线程把自己的node节点push到_cxq列表中;

3、node节点push到_cxq列表之后,通过自旋尝试获取锁,如果还是没有获取到锁,则通过park将当前线程挂起,等待被唤醒,实现如下:


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z84eXtzV-1571562703110)(https://uploadfiles.nowcoder.com/files/20191020/5088755_1571562670865_4685968-e797fdcdc32a2f8e.png)]


4、当该线程被唤醒时,会从挂起的点继续执行,通过ObjectMonitor::TryLock尝试获取锁,TryLock方法实现如下:


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sJC8vMmz-1571562703111)(https://uploadfiles.nowcoder.com/files/20191020/5088755_1571562670568_4685968-17d10b24c3369844.png)]


其本质就是通过CAS设置monitor的_owner字段为当前线程,如果CAS成功,则表示该线程获取了锁,跳出自旋操作,执行同步代码,否则继续被挂起;

monitor释放

当某个持有锁的线程执行完同步代码块时,会进行锁的释放,给其它线程机会执行同步代码,在HotSpot中,通过退出monitor的方式实现锁的释放,并通知被阻塞的线程,具体实现位于ObjectMonitor::exit方法中。

Java同步关键字synchronize底层实现原理(下)

1、如果是重量级锁的释放,monitor中的_owner指向当前线程,即THREAD == _owner;

2、根据不同的策略(由QMode指定),从cxq或EntryList中获取头节点,通过ObjectMonitor::ExitEpilog方法唤醒该节点封装的线程,唤醒操作最终由unpark完成,实现如下:

void ObjectMonitor::ExitEpilog(Thread * Self, ObjectWaiter * Wakee) {
  assert(_owner == Self, "invariant");

  // Exit protocol:
  // 1. ST _succ = wakee
  // 2. membar #loadstore|#storestore;
  // 2. ST _owner = NULL
  // 3. unpark(wakee)

  _succ = Wakee->_thread;
  ParkEvent * Trigger = Wakee->_event;

  // Hygiene -- once we've set _owner = NULL we can't safely dereference Wakee again.
  // The thread associated with Wakee may have grabbed the lock and "Wakee" may be
  // out-of-scope (non-extant).
  Wakee  = NULL;

  // Drop the lock
  OrderAccess::release_store(&_owner, (void*)NULL);
  OrderAccess::fence();                               // ST _owner vs LD in unpark()

  DTRACE_MONITOR_PROBE(contended__exit, this, object(), Self);
  Trigger->unpark();

  // Maintain stats and report events to JVMTI
  OM_PERFDATA_OP(Parks, inc());
}

3、被唤醒的线程,继续执行monitor的竞争;

上一篇:编程填空:第i位取反


下一篇:《MapReduce 2.0源码分析与编程实战》一2.1 从头开始