Mark Word 参考表
假设存在三个线程:线程A(线程编号为 A)、线程B(线程编号为 B)、线程C(线程编号为 C)
1、线程A首次访问同步块时
- 线程A进入synchronized 同步块时。线程A会通过CAS设置Mark Word的线程ID为自己的ID,如果成功, 则获取锁。
Mark Word 为: A|Epoch|age|1|01
当前为偏向锁。
2、线程A再次访问时
- 线程A会判断Mark Word的线程ID是否为自己的ID,如果是,则不需要CAS了,直接执行代码块。
3、当线程B访问同步块时(线程A正在访问同步块中)
- 线程B进入synchronized 同步块时。
- 线程A会通过CAS设置Mark Word的线程ID为自己的ID
如果失败,将升级锁为轻量级锁,暂停线程A,Mark Word的线程ID设置为null, 然后唤醒线程A
4、被唤醒的线程A和线程B在轻量级锁中竞争
- 线程A和线程B分别在自己的栈空间中新建一块存储锁记录的空间,然后将锁对象的Mark Word信息复制到开辟的空间中,然后线程A和线程B进行CAS将对象中Mark Word中的锁记录指针指向锁开辟拷贝的空间。
- 假如线程B竞争成功,则线程A进入自旋状态来修改对象中Mark Word中的锁记录指针指向锁开辟拷贝的空间。如果失败则进入重量级锁。
5、进入重量级锁。(锁无法降级)
此处将会用到monitor对象!!!
monitor对象重要属性说明:
-
_owner:指向持有ObjectMonitor对象的线程
-
_WaitSet:存放处于wait状态的线程队列
-
_EntryList:存放处于等待锁block状态的线程队列
-
_recursions:锁的重入次数
-
_count:用来记录该线程获取锁的次数
假如当前线程A、B、C同时访问同步块。假如A获取到锁,也就会将 monitor 对象中的 _owner 的值赋值为当前线程ID。B、
C线程会进入EntryList中。count =1 , recursions=1。假如A线程第二次进入同步快,count = 2, recursions=2,当前线程退
出时,count和recursions会减一,直到count=0, recursions=0时,说明线程A释放了monitor锁,然后会唤醒EntryList中的线
程,EntryList线程会竞争monitor,竞争到了,和线程A的操作一致。
WaitSet 主要是存放在同步块中执行 wait 方法的线程。配合 EntryList 就是 对象 的 wait 和 notify(notifyAll) 的底层实现。