java并发编程中,对象-Monitor-MarkWord之间的关系,你知道吗?

218 阅读6分钟

背景

在并发编程学习中,提及到了对象-Monitor-MarkWord,看完一遍视频后,自己梳理这三者之间关系的时候,怎么根据对象获取Moniter这块,不是很清楚,于是进行了查询整理,先将结果记录在此

对象-Monitor-MarkWord之间的关系

在Java中,对象、Monitor(监视器)和Mark Word(标记字)之间的关系是理解Java并发机制和对象内存布局的关键。它们共同作用于对象的同步和锁机制。以下是详细的解释:

1. 对象 (Object)

  • 定义:对象是类的实例,包含数据(字段)和行为(方法)。每个对象都有自己的状态和行为。
  • 内存布局:在Java虚拟机(JVM)中,对象的内存布局分为几个部分:
    • 对象头 (Object Header):包含对象的元数据信息,如哈希码、GC年龄等。
    • 实例数据 (Instance Data):存储对象的字段值。
    • 对齐填充 (Padding):用于保证对象的内存对齐。

2. Monitor (监视器)

  • 定义:Monitor是一个抽象的概念,用于实现Java中的同步机制。每个对象都有一个与之关联的Monitor,它负责控制对对象的访问,确保同一时间只有一个线程可以执行被synchronized修饰的方法或代码块。
  • 工作原理
    • 当一个线程进入一个synchronized方法或代码块时,它会尝试获取该对象的Monitor。
    • 如果Monitor空闲(即没有其他线程持有它),当前线程可以获得Monitor并继续执行。
    • 如果Monitor已经被其他线程持有,当前线程将被阻塞,直到持有Monitor的线程释放它。
    • 当线程退出synchronized方法或代码块时,它会释放Monitor,允许其他等待的线程获取它。

3. Mark Word (标记字)

  • 定义:Mark Word是对象头的一部分,通常占用64位(在64位JVM上),用于存储对象的元数据信息。Mark Word的内容并不是固定的,而是根据对象的状态动态变化的。
  • 内容
    • 哈希码 (Hash Code):默认情况下,Mark Word存储对象的哈希码。
    • GC年龄 (GC Age):记录对象在垃圾回收过程中存活的次数。
    • 锁状态 (Lock State):当对象被锁定时,Mark Word会存储锁的相关信息,如指向Monitor的指针、偏向锁的线程ID等。
    • 偏向锁 (Biased Locking):如果启用了偏向锁,Mark Word会存储偏向线程的ID,表示该对象偏向于某个特定线程。
    • 轻量级锁 (Lightweight Locking):在轻量级锁状态下,Mark Word会存储指向栈中锁记录的指针。
    • 重量级锁 (Heavyweight Locking):在重量级锁状态下,Mark Word会存储指向Monitor对象的指针。

4. 对象、Monitor和Mark Word的关联

  • 对象头中的Mark Word:每个对象的Mark Word是对象头的一部分,它包含了对象的锁状态信息。当对象被锁定时,Mark Word会根据锁的状态进行更新,存储不同的信息。

  • Monitor与Mark Word的关系:Monitor本身并不是直接存储在对象头中,而是通过Mark Word间接关联。具体来说:

    • 无锁状态下,Mark Word只存储哈希码、GC年龄等信息。
    • 偏向锁状态下,Mark Word存储偏向线程的ID,表示该对象偏向于某个特定线程。如果多个线程频繁访问同一个对象,偏向锁可以减少锁的竞争。
    • 轻量级锁状态下,Mark Word存储指向栈中锁记录的指针。轻量级锁使用CAS(Compare-And-Swap)操作来避免线程切换,提高性能。
    • 重量级锁状态下,Mark Word存储指向Monitor对象的指针。Monitor对象包含了一个等待队列,用于管理等待获取锁的线程。重量级锁会导致线程阻塞,性能较低,但适用于高竞争场景。
  • 锁升级机制:JVM为了优化锁的性能,引入了锁升级机制。锁的状态会根据竞争情况从无锁状态逐步升级到重量级锁:

    1. 无锁状态:对象未被锁定,Mark Word只存储哈希码等信息。
    2. 偏向锁:如果只有一个线程频繁访问对象,JVM会将锁偏向该线程,减少锁的竞争。
    3. 轻量级锁:当有多个线程竞争时,JVM会将锁升级为轻量级锁,使用CAS操作来避免线程切换。
    4. 重量级锁:如果竞争非常激烈,JVM会将锁升级为重量级锁,导致线程阻塞,性能较低。

5. 锁的几种状态

  • 无锁状态:对象未被锁定,Mark Word存储哈希码等信息。
  • 偏向锁:对象偏向于某个特定线程,Mark Word存储偏向线程的ID。
  • 轻量级锁:对象被多个线程竞争,Mark Word存储指向栈中锁记录的指针。
  • 重量级锁:对象被多个线程激烈竞争,Mark Word存储指向Monitor对象的指针。

6. 示例说明

假设我们有一个简单的Java类:

public class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

在这个例子中:

  • Counter类的每个实例都有一个与之关联的Monitor。
  • 当调用synchronized方法increment()getCount()时,线程会尝试获取该对象的Monitor。
  • Monitor的状态会根据竞争情况从无锁状态逐步升级到重量级锁:
    • 如果只有一个线程访问Counter对象,JVM可能会使用偏向锁,减少锁的竞争。
    • 如果有多个线程同时调用increment()getCount(),JVM可能会将锁升级为轻量级锁或重量级锁,以确保线程安全。

7. 总结

  • 对象:是类的实例,包含数据和行为。
  • Monitor:是Java中用于实现同步机制的抽象概念,每个对象都有一个与之关联的Monitor,用于控制对对象的访问。
  • Mark Word:是对象头的一部分,存储对象的元数据信息,包括锁状态。Mark Word根据对象的锁状态动态变化,存储不同的信息。
  • 关联:Monitor通过Mark Word间接与对象关联。Mark Word根据锁的状态存储不同的信息,如偏向线程ID、锁记录指针或Monitor指针。锁的状态会根据竞争情况从无锁状态逐步升级到重量级锁,以优化性能。

理解对象、Monitor和Mark Word之间的关系有助于你更好地理解Java的同步机制和锁的实现原理,从而编写更高效、更安全的多线程代码。