monitor监视器锁
在HotSpot虚拟机中,monitor是由ObjectMonitor实现的。其源码是用c++来实现的。

monitor竞争
当多个线程执行到同步代码块时就会产生竞争,synchronized会执行monitorenter指令,最终会调用C++的ObjectMonitor::enter方法。


竞争流程概括小结
1.通过CAS尝试把monitor的owner字段设置为当前线程。
2.如果设置之前的owner指向当前线程,说明当前线程再次进入monitor,即重入锁,执行recursions++,记录锁重入的次数。
3.如果当前线程是第一次进入该monitor,设置recursions为1,_owner为当前线程,该线程成功获得锁并返回。
4.如果获取锁失效,则进入等待队列,等待锁的释放。
monitor等待
竞争失败调用的是ObjectMonitor对象的EnterI方法




等待流程概括小结
1.当前线程被封装成ObjectWaiter对象的node,状态设置为ObjectWaiter::TS_CXQ。
2.在for循环中,通过CAS把node节点push到_cxq列表中,同一时刻可能有多个线程把自己的node节点push到cxq列表中。
3.node节点push到_cxq列表之后,通过自旋尝试获取锁,如果没有获取到锁,则通过park将当前线程挂起,等待被唤醒。
4.当线程被唤醒时,会从挂起的点继续执行,通过ObjectMonitor::TryLock尝试获取锁。
monitor释放
当某个持有锁的线程执行完同步代码块时,会进行锁的释放,给其它线程机会执行同步代码。调用的是ObjectMonitor对象的Exit方法。




recursions对应线程的重入次数,可重入锁,当减为0时说明线程完全出了同步代码块并释放锁,同时根据不同的策略(QMode指定)去唤醒正在等待阻塞的线程,从等待链表_cxq和_EntryList中获取头结点,通过ExitEpilog方法唤醒该节点封装的线程,唤醒操作最终由UNpark操作。

monitor是重量级锁
ObjectMonitor的函数调用中会涉及到Atomic::cmpxchg_ptr,Atomic::inc_ptr等内核函数,执行同步代码块,没有竞争到说的对象会park()被挂起,竞争到锁的线程会unpark()唤醒。这个时候会存在操作系统用户态(初始进程都运行与用户空间)和内核态(调用系统调用某些操作)的切换,这种切换回会消耗大量的系统资源。