一、ObjectMonitor结构体
Monitor是基于C++代码中的ObjectMonitor结构体实现的。
ObjectMonitor() {
_header = NULL;
_count = 0; // 由于synchronized是可重入锁,count用于记录当前对象锁拥有者线程获取锁的次数
_waiters = 0,
_recursions = 0;
_object = NULL;
_owner = NULL;
_WaitSet = NULL; // 调用了wait方法,处于WAIT/TIME_WAIT的线程,会被加入到WaitSet
_WaitSetLock = 0 ;
_Responsible = NULL ;
_succ = NULL ;
_cxq = NULL ;
FreeNext = NULL ;
_EntryList = NULL ; // 处于等待锁block状态的线程,会被加入到EntryList
_SpinFreq = 0 ;
_SpinClock = 0 ;
OwnerIsThread = 0 ;
}
二、Monitor原理
在Java虚拟机(HotSpot)中,对象监视器主要是基于ObjectMonitor结构体中的EntrySet、WaitSet两个队列以及计数器count实现的。
- 当有多个线程同时想获取某个对象锁时,首先会进入EntryList队列
- 当某个线程获取到对象锁时,线程成为对象锁的拥有者,准备开始运行加锁代码块时,执行字节码指令
monitorenter
,此时count ++;
- 当对象锁的拥有者线程再次获取锁时,由于
synchronized
锁是可重入的,此时进行count ++
,而不是在EntryList队列中阻塞等待锁; - 每个加锁代码块运行完成或因发生异常退出时,会执行
monitorexit
字节码指令,此时count --;
,当count变为0是,对象锁的拥有者线程释放锁。 - 拥有锁的线程在运行过程中调用了
wait()
方法,那么线程会进入到WaitSet对象,等待被notify()
或等待的时间已到,才有可能再次成为对象锁的拥有者。