Mark Word

先说一下synchronized的历史吧,在jdk1.6之前synchronized就是单纯一个重量级锁,在jdk1.6的时候,有一个叫Doug Lea的大哥看不过去了,明明很多情况都是不需要重量级锁的,只需要标记一下,所以这个大哥就开发一个ReentrantLock,无竞争的情况在java层面就完成了加锁解锁,这时候吧,jdk可能觉得面子上有点那啥,便开始优化synchronized,然后就产生了我们熟知的偏向锁,轻量级锁,重量级锁。

因为网上大部分的文章写mark word的解释基本都是基于32位jdk,这里我简单介绍一下64位jdk中,mark down的组成,和锁升级过程标志位的变化。

1、java对象布局

java的对象布局是由对象头、实例数据、数据对齐组成
但实际情况并不一定,后面我们引用下面的maven依赖来进行证明


    org.openjdk.jol
    jol-core
    0.9

2、对象布局的证明

public class Test {
    public static void main(String[] args) {
         A a = new A();
        System.out.println(ClassLayout.parseInstance(a).toPrintable());
    }
}
class A {
    boolean a = true;
}

Mark Word_第1张图片
对象头

(1)在这里我们发现对象头的确是又上面三个部分组成.
(2)我们将boolean改为int后

Mark Word_第2张图片
对象头

发现没有数据填充的部分,这时候我们并不需要数据填充

(3)同理,我们将变量a删除后,没有了示例数据这一部分

Mark Word_第3张图片
对象头

3、我们可以得出结论

对齐填充并不是必然存在的,也没有什么特别的意义,他仅仅起着占位符的作用,由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说,就是对象的大小必须是8字节的整数倍。而对象头正好是8字节的倍数,因此,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。

4、mark word

对象头由两部分组成,一部分用于存储自身的运行时数据,称之为mark word,另外一部分是类型指针,及对象指向它的类元数据的指针。这里我们只研究一下mark word
OpenJdk官网对于mard word的定义

Mark Word_第4张图片
mark word

每个对象头的第一个字。通常是一组位字段,包括同步状态和标识哈希码。也可以是指向同步相关信息的指针(具有特征性的低位编码)。在GC期间,可以包含GC状态位。

我们再看hotspot的源码,里面有一段注释

Mark Word_第5张图片
注释

Mark Word_第6张图片
结构图

首先无锁、偏向锁、轻量锁大家应该都很清楚,但是图中的无锁可偏向和无锁不可偏向我在这里解释下,
我们知道偏向锁会在mark word中记录偏向线程的id,但是根据上图,我们可以发现,hashcode和偏向线程的id的位置是有冲突的,所以在不可偏向时就是我们计算了这个类的hashcode,这时候锁会直接升级成轻量级锁,后面我们会通过例子来证明。

5、hashcode

首先我们计算一下hashcode 再和mark word进行比较

这里我要先说明下,后面我们输出的mark word和我们期望的 在位置上是相反的,这是由于cpu的缘故,这里不做解释
jdk8中,有一个偏向锁的延迟开启,我们需要把延迟时间设置为0
-XX:BiasedLockingStartupDelay=0

Mark Word_第7张图片
无锁不可偏向

首先我们可以看到 实例的hashcode和mark word里面标记的一样,并且现在是无锁不可偏向状态
下面不计算hashcode再看一下锁的标志位


Mark Word_第8张图片
无锁可偏向

6、模拟无锁升级偏向锁过程

public class B {
    static A a = new A();
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(){
            @Override
            public void run() {
                synchronized (a){
                    System.out.println("t1:");
                }
            }
        };
        t1.start();
        t1.join();
        System.out.println(ClassLayout.parseInstance(a).toPrintable());
    }
}
class A {
}
Mark Word_第9张图片
无锁升级偏向锁

7、模拟无锁升级轻量级锁过程

public class B {
    static final A a = new A();
    static volatile int flag = 1;
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(){
            @Override
            public void run() {
                synchronized (a){
                    System.out.println("t1");
                    System.out.println(ClassLayout.parseInstance(a).toPrintable());
                }
                flag = 2;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        Thread t2 = new Thread(){
            @Override
            public void run() {
                while (flag!=2) {
                }
                synchronized (a){
                    System.out.println("t2");
                    System.out.println(ClassLayout.parseInstance(a).toPrintable());
                }
            }
        };

        t1.start();
        Thread.sleep(100);
        t2.start();
    }
}
class A {
}
Mark Word_第10张图片
无锁升级轻量级锁

8、将7中代码加入hashcode计算

Mark Word_第11张图片
加入hashcode之后的无锁升级轻量级锁

9、重量级锁这里就不再演示,存在竞争即升级为重量级锁

你可能感兴趣的:(Mark Word)