Monitor概念介绍
一、Java对象头
HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。
HotSpot虚拟机的对象头包括三部分信息:
- Mark Word
- 指向类的指针
- 数组长度
普通对象
以 32 位虚拟机为例
Klass Word:指向对象的类型(一个指针找到它的类对象)
一个int 类型占4个字节,而一个Integer对象占8 + 4个字节
数组对象
说明
Object的对象头,分为两部分
第一部分是
Mark Word
,用来存储对象的运行时数据比如:hashcode,GC分代年龄,锁状态,持有锁信息,偏向锁的thread ID等等。在64位的虚拟机中,Mark Word是64bits,如果是在32位的虚拟机中Mark Word是32bits
第二部分就是
Klass Word
,Klass Word是一个类型指针,指向class的元数据,JVM通过Klass Word来判断该对象是哪个class的实例。
Mark Word结构
- 32位虚拟机下:MarkWord有4个字节 最后2个bit位表示状态
说明
age:垃圾回收时的分代年龄
biased_lock:是否为偏向锁
01/00(biased_lock后一位):加锁状态
Normal:对象正常状态
当对对象进行相应改变,如施加轻量级锁、重量级锁,GC时,相应的Mark Word Structure会发生改变
状态说明
状态 | 标志位 | 存储内容 |
---|---|---|
未锁定 | 01 | 对象哈希码、对象分代年龄 |
轻量级锁定 | 00 | 指向锁记录的指针 |
膨胀(重量级锁定) | 10 | 执行重量级锁定的指针 |
GC标记 | 11 | 空(不需要记录信息) |
可偏向 | 01 | 偏向线程ID、偏向时间戳、对象分代年龄 |
- 64位虚拟机下:MarkWord有8个字节 最后2个bit位表示状态
二、Monitor概念
Monitor被翻译为监视器或管程(通常称为“锁”)
每个Java对象都可以关联一个Monitor对象(JVM提供),如果使用synchronized给对象上锁(重量级)之后,该对象头的Mark Word中就被设置指向Monitor对象的指针
Monitor结构
- Monitor属性含义
- Owner:锁的拥有者,唯一性,当线程尝试获得锁时若有其他线程引用,则无法获得
- EntryList:阻塞(等待)队列,其他线程无法获得锁时,则一起进入阻塞队列,但是一旦线程释放锁,它们是竞争获得锁(而不是先来后到)
- WaitSet:存放处于wait状态的线程队列,即调用wait()方法的线程
obj对象的MarkWord
结构指向Monitor
对象,当t2执行到synchronized
方法时,首先判断临界区代码是否加锁。
t2首先判断Monitor Owner是否有线程引用,无则获得锁,执行临界区代码,其他线程t1,t3则进入阻塞队列,等待t2释放锁。
Monitor调用步骤
- 刚开始
Monitor
中Owner
为null
- 当
Thread-2
执行synchronized(obj)
就会将Monitor的所有者Owner置为Thread-2
,Monitor
中只能有一个Owner
- 在
Thread-2
上锁的过程中,如果Thread-3,Thread-4, Thread-5
也来执行synchronized(obj)
, 就会进入EntryList BLOCKED
Thread-2
执行完同步代码块的内容,然后唤醒EntryList中等待的线程来竞争锁,竞争的时是非公平的- 图中
WaitSet
中的Thread-0
,Thread-1
是之前获得过锁,但条件不满足进入WAITING状态的线程,后面讲wait-notify
时会分析
注意
- synchronized必须是进入同一个对象的monitor才有上述的效果
- 不加synchronized的对象不会关联监视器,不遵从以上规则