1、Java对象头
-
Java对象构成:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding),图示:
-
对象头:以32位虚拟机为例,Java对象头构成如下
-
普通对象:
Object Header(64 bits) Mark Word(32 bits) Klass Word(32 bits) -
数组对象:
Object Header(96 bits) Mark Word(32 bits) Klass Word(32 bits) Array Length(32 bits) -
-
Mark Word结构:
Mark Word(32 bits) | State | ||||
hashcode:25 | age:4 | biased_lock:0 | 01 | Normal | |
thread:23 | epoch:2 | age:4 | biased_lock:1 | 01 | Biased |
ptr_to_lock_record:30 | 00 | LightWight Locked | |||
ptr_to_heavyweight_monitor:30 | 10 | HeavyWeight Locked | |||
11 | Marked for GC |
-
hashcode:哈希码,只有第一次调用对象.hashcode()之后,才会赋值,默认00000000
-
age:分代年龄,
-
biased_lock:是否偏向
-
01:正常或者偏向,00:轻量级锁,10:重量级锁,11:标记为可垃圾回收
-
thread:线程地址
-
epoch:时代、纪元
-
ptr_to_lock_record:锁记录地址
-
ptr_to_heavyweight_monitor:Monitor对象地址
-
参考地址:
2、Monitor
Monitor翻译为管程或监视器。
每个Java对象都可以关联一个Monitor对象,如果使用synchronized给对象上锁(总量级)之后,改对象头的Mark Word中被设置为指向Monitor的指针。
加锁(重量级)示意图:
工作原理,以加锁(重量级锁)为例:
- 初始的时候,Monitor的Owner 为null,表示没有线程占用改锁对象
- 当线程Thread-1执行synchronized(Object)之时,Object对象会关联一个Monitor对象,通过Java对象头的Makr Word指向关联的Monitor对象。
- 此时会将Moniotor对象的Owner置为指向Thread-1的指针,Monitor只能有一个Owner。
- 在Thread-1上锁后,有后续的Thread-2,Thread-3执行synchronized,需要获取锁对象,发现Owner不为空,此时,这些线程会进入Monitor的EntryList队列。
- 如果有线程对象执行了wait()方法,会进入WaitSet集合;除非通过同一对象的notify或者notifyAll方法唤醒,不然一直在改集合中等待。
- 当线程Thread-1执行完同步代码块的时候,释放锁对象,即Monitor对象的Owner置为null,同时会唤醒在EntryList上阻塞的线程,竞争锁对象。
注意事项:
- synchronized必须是进入同一个对象的monitor时才有上述效果。
- 不加synchronized的对象不好关联监视器,不遵从以上规则