面试被问到了wait和sleep区别,才知道这种使用场景完全不同的东西还能问区别…不过,确实没看过这俩的源码,来看一下。
解释器映射op的过程
我这里看的是art源码,而非jvm源码。本人对bytecode到真正执行代码的映射暂无认知,经高人指点是所有的解释器实现是在interpreter目录中。
入口是interpreter.cpp#EnterInterpreterFromInvoke -> Execute -> ExecuteSwitch -> interpreter_switch_impl.h#ExecuteSwitchImpl -> ExecuteSwitchImplCpp -> 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。
Thread#sleep
Thread持有一个Object对象,叫做lock。Sleep是拿到这个对象后传给了native。
java_lang_Thread.cc#Thread_sleep -> Monitor#wait !!!这里居然是直接调用wait,面试官站出来,这俩有什么区别!!!