背景
在并发编程学习中,提及到了对象-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为了优化锁的性能,引入了锁升级机制。锁的状态会根据竞争情况从无锁状态逐步升级到重量级锁:
- 无锁状态:对象未被锁定,Mark Word只存储哈希码等信息。
- 偏向锁:如果只有一个线程频繁访问对象,JVM会将锁偏向该线程,减少锁的竞争。
- 轻量级锁:当有多个线程竞争时,JVM会将锁升级为轻量级锁,使用CAS操作来避免线程切换。
- 重量级锁:如果竞争非常激烈,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的同步机制和锁的实现原理,从而编写更高效、更安全的多线程代码。