Object.wait和monitor源码

面试被问到了wait和sleep区别,才知道这种使用场景完全不同的东西还能问区别…不过,确实没看过这俩的源码,来看一下。

解释器映射op的过程

我这里看的是art源码,而非jvm源码。本人对bytecode到真正执行代码的映射暂无认知,经高人指点是所有的解释器实现是在interpreter目录中。

入口是interpreter.cpp#EnterInterpreterFromInvoke -> Execute -> ExecuteSwitch -> interpreter_switch_impl.h#ExecuteSwitchImpl -> ExecuteSwitchImplAsm 断到汇编里了…后面部分是猜的-> interpreter_switch_impl-inl.h#OP_NAME(见list

Monitor enter和exit

这个是基础,因为wait必须在monitor保护下。monitor相关的背景知识

monitor#enter

interpreter_switch_impl-inl.h#MONITOR_ENTER -> 这里会把寄存器里的对象拿出来,传给interpreter_common.h#DoMonitorEnter -> object-inl.h#MonitorEnter -> monitor.cc#MonitorEnter

  • 获取锁字段,Object#GetLockWord,锁字段是在对象头中的32bit数据
  • 根据锁类型来进行下一步操作
    • 无锁,直接锁上thin lock
    • thin lock,检查thin lock owner(thread id)是否与当前线程id相同。
      • 如果相同,获取thin lock个数,未超阈值会更新lock word,如果更新失败会有个自旋;超过阈值会InflateThinLocked。(获取的时候都会调用CheckReadBarrierState,没看懂干嘛了。)
      • 如果不同,会自旋尝试获取thin lock阈值次。如果超过自旋阈值会先yeild,再等待调度;如果未超会InflateThinLocked。
    • fat lock,因为有多线程,所以先atomic_thread_fence保护上。然后LockWord#FatLockMonitor(返回一个Monitor对象)-> Monitor#(Try)Lock
      • TryLock,基本上就是操作c++的mutex了,如果成功就直接return了
      • 大概率当前线程不是Monitor的owner
      • 把自己设置到线程的SetMonitorEnterObject上
      • 靠mutex获取锁,释放cpu
      • 锁获取成功,修改owner

monitor#InflateThinLocked

  • 看起来是利用TheadList来做等待的 // TODO
  • 利用MonitorPool构造一个Monitor
  • Monitor#Install,替换对象头
  • 加到MonitorList中。看起来只是为了不释放?

Object#wait

仍然是走到了Monitor#wait,整体就是一个线程等待队列,类似于AQS,核心是AppendToWaitSet和RemoveFromWaitSet。

上一篇:*媒体人,如何用飞项摆脱低效的“997”?


下一篇:DB2监控之分析CPU高