Java并发(十九)----Monitor原理及Synchronized原理

发布时间:2023年12月17日

1、Java 对象头

以 32 位虚拟机为例

普通对象

|--------------------------------------------------------------|
| ? ? ? ? ? ? ? ? ? ? Object Header (64 bits) ? ? ? ? ? ? ? ? ?|
|------------------------------------|-------------------------|
| ? ? ? ?Mark Word (32 bits) ? ? ? ? | ? ?klass Word (32 bits) |
|------------------------------------|-------------------------|

数组对象

|---------------------------------------------------------------------------------|
| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Object Header (96 bits) ? ? ? ? ? ? ? ? ? ? ? ? |
|--------------------------------|-----------------------|------------------------|
| ? ? ? ?Mark Word(32bits) ? ? ? | ? ?Klass Word(32bits) | ?array length(32bits) ?|
|--------------------------------|-----------------------|------------------------|

其中 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 ? ? | Lightweight Locked |
|-------------------------------------------------------|--------------------|
| ? ? ? ? ? ? ? ptr_to_heavyweight_monitor:30 ?| 10 ? ? | Heavyweight Locked |
|-------------------------------------------------------|--------------------|
| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| 11 ? ? | ? ?Marked for GC ? |
|-------------------------------------------------------|--------------------|

64 位虚拟机 Mark Word

|--------------------------------------------------------------------|--------------------|
| ? ? ? ? ? ? ? ? ? ? ? ?Mark Word (64 bits) ? ? ? ? ? ? ? ? ? ? ? ? | ? ? ? State ? ? ? ?|
|--------------------------------------------------------------------|--------------------|
| unused:25 | hashcode:31 | unused:1 | age:4 | biased_lock:0 | 01 ? ?| ? ? ? Normal ? ? ? |
|--------------------------------------------------------------------|--------------------|
| thread:54 | epoch:2 ? ? | unused:1 | age:4 | biased_lock:1 | 01 ? ?| ? ? ? Biased ? ? ? |
|--------------------------------------------------------------------|--------------------|
| ? ? ? ? ? ? ptr_to_lock_record:62 ? ? ? ? ? ? ? ? ? ? ? ? ?| 00 ? ?| Lightweight Locked |
|--------------------------------------------------------------------|--------------------|
| ? ? ? ? ? ? ptr_to_heavyweight_monitor:62 ? ? ? ? ? ? ? ? ?| 10 ? ?| Heavyweight Locked |
|--------------------------------------------------------------------|--------------------|
| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| 11 ? ?| ? ?Marked for GC ? |
|--------------------------------------------------------------------|--------------------|

参考资料

jvm - What is in Java object header? - Stack Overflow

2、Monitor 原理

Monitor 被翻译为监视器管程

每个 Java 对象都可以关联一个 Monitor 对象,如果使用 synchronized 给对象上锁(重量级)之后,该对象头的 Mark Word 中就被设置指向 Monitor 对象的指针

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 的对象不会关联监视器,不遵从以上规则

3、synchronized 原理

static final Object lock = new Object();
static int counter = 0;
?
public static void main(String[] args) {
 ? ?synchronized (lock) {
 ? ? ? ?counter++;
 ?  }
}

对应的字节码为

public static void main(java.lang.String[]);
 ? ?descriptor: ([Ljava/lang/String;)V
 ? ?flags: ACC_PUBLIC, ACC_STATIC
 ? ?Code:
 ? ? ?stack=2, locals=3, args_size=1
 ? ? ? ? 0: getstatic ? ? #2 ? ? ? ? ? ? ? ? ?// <- lock引用 (synchronized开始)
 ? ? ? ? 3: dup ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 复制一份引用
 ? ? ? ? 4: astore_1 ? ? ? ? ? ? ? ? ? ? ? ? ?// lock引用 -> slot 1
 ? ? ? ? 5: monitorenter ? ? ? ? ? ? ? ? ? ? ?// 将 lock对象 MarkWord 置为 Monitor 指针
 ? ? ? ? 6: getstatic ? ? #3 ? ? ? ? ? ? ? ? ?// <- i
 ? ? ? ? 9: iconst_1 ? ? ? ? ? ? ? ? ? ? ? ? ?// 准备常数 1
 ? ? ? ?10: iadd ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// +1
 ? ? ? ?11: putstatic ? ? #3 ? ? ? ? ? ? ? ? ?// -> i
 ? ? ? ?14: aload_1 ? ? ? ? ? ? ? ? ? ? ? ? ? // <- lock引用
 ? ? ? ?15: monitorexit ? ? ? ? ? ? ? ? ? ? ? // 将 lock对象 MarkWord 重置, 唤醒 EntryList
 ? ? ? ?16: goto ? ? ? ? ?24                 ?// 19-23 为异常处理
 ? ? ? ?19: astore_2 ? ? ? ? ? ? ? ? ? ? ? ? ?// e -> slot 2 
 ? ? ? ?20: aload_1 ? ? ? ? ? ? ? ? ? ? ? ? ? // <- lock引用
 ? ? ? ?21: monitorexit ? ? ? ? ? ? ? ? ? ? ? // 将 lock对象 MarkWord 重置, 唤醒 EntryList
 ? ? ? ?22: aload_2 ? ? ? ? ? ? ? ? ? ? ? ? ? // <- slot 2 (e)
 ? ? ? ?23: athrow ? ? ? ? ? ? ? ? ? ? ? ? ? ?// throw e
 ? ? ? ?24: return
 ? ? ?Exception table:                      // 异常检测
 ? ? ? ? from ? ?to ?target type
 ? ? ? ? ? ? 6 ? ?16 ? ?19 ? any            // 6-16 行出现异常 目标为19行
 ? ? ? ? ? ?19 ? ?22 ? ?19 ? any            // 19-22 行出现异常 目标为19行
 ? ? ?LineNumberTable:
 ? ? ? ?line 8: 0
 ? ? ? ?line 9: 6
 ? ? ? ?line 10: 14
 ? ? ? ?line 11: 24
 ? ? ?LocalVariableTable:
 ? ? ? ?Start ?Length ?Slot ?Name ? Signature
 ? ? ? ? ? ?0 ? ? ?25 ? ? 0 ?args ? [Ljava/lang/String;
 ? ? ?StackMapTable: number_of_entries = 2
 ? ? ? ?frame_type = 255 /* full_frame */
 ? ? ? ? ?offset_delta = 19
 ? ? ? ? ?locals = [ class "[Ljava/lang/String;", class java/lang/Object ]
 ? ? ? ? ?stack = [ class java/lang/Throwable ]
 ? ? ? ?frame_type = 250 /* chop */
 ? ? ? ? ?offset_delta = 4

注意

方法级别的 synchronized 不会在字节码指令中有所体现

文章来源:https://blog.csdn.net/FaithWh/article/details/135050280
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。