偏向锁、轻量级锁和重量级锁在对象头中的展示

1、java对象头分析
假设我们理解一个对象头主要两部分组成(数组对象除外,数组对象的对象头还包含一个数组长度),那么
一个java的对象头多大呢?我们从下图的hotspot源码注释中得知到一个mark word一个是64bit,那么klass的长度是多少呢?
在这里插入图片描述
所以我们需要想办法来获得java对象头的详细信息,验证一下他的大小,验证一下里面包含的信息是否正确。
因此我们可以采用JOLjar包打印出具体的对象头来分析对象头具体的结构。

根据上述利用JOL打印的对象头信息可以知道一个对象头是12B,其中8B是mark word 那么剩下的4B就是klass
word了,和锁相关的就是mark word了,那么接下来重点分析mark word里面信息,在无锁的情况下markword当中的前56bit存的是对象的hashcode,图中红色部分存储的是该对象的hashcode,上图由于没有计算hashcode,所以表示的全为0,计算了hashcode之后如下图所示。
在这里插入图片描述
由于CPU采用小端模式(什么是小端模式在笔记最后一页),因此图中二进制所对应的十六进制应为:10001110 ----8e, 00001011—0b, 00101010—2a, 00001111–0f。而第一个字节当中的八位分别存的就是分代年龄、偏向锁信息,和对象状态,这个8bit分别表示的信息如下图(其实上图也有信息),这个图会随着对象状态改变而改变。

2、偏向锁、轻量级锁和重量级锁在对象头中的标识

在这里插入图片描述
1)无锁状态
在这里插入图片描述
2)偏向锁状态
在这里插入图片描述

 static A a;
    public static void main(String[] args) throws Exception {
        /*Thread.sleep(5000);*/
        a= new A();
        out.println("befor lock");
        out.println(ClassLayout.parseInstance(a).toPrintable());
        synchronized (a){
            out.println("lock ing");
            /*out.println(ClassLayout.parseInstance(a).toPrintable());*/
        }
        out.println("after lock");
        out.println(ClassLayout.parseInstance(a).toPrintable());
    }
}

输出结果:
在这里插入图片描述
上面这个程序只有一个线程去调用sync方法,故而讲道理应该是偏向锁,但是你会发现输出的结果(第一个字节)依然是00000001和无锁的时候一模一样,其实这是因为虚拟机在启动的时候对于偏向锁有延迟,比如把上述代码当中的睡眠注释掉结果就会不一样了,结果会变成00000101当然为了方便测试我们可以直接通过JVM的参数来禁用延迟
-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0,(除了这8bit,其他bit存储了线程信息和epoch),需要注意的after lock,退出同步后依然保持了偏向信息。偏向锁为什么会出现延迟:启动JVM会出现大量同步方法出现消除锁出现轻量级锁,sun jdk规定有延迟4S出现偏向锁。将上面代码中国的主线程睡眠四秒之后执行就会出现偏向锁属于个人学习理解
3)轻量级锁
在这里插入图片描述
4)重量级锁
在这里插入图片描述

static A a;
public static void main(String[] args) throws Exception {
    //Thread.sleep(5000);
    a = new A();
    out.println("befre lock");
    out.println(ClassLayout.parseInstance(a).toPrintable());//无锁

    Thread t1= new Thread(){
        public void run() {
            synchronized (a){
                try {
                    Thread.sleep(5000);
                    System.out.println("t1 release");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };
    t1.start();
    Thread.sleep(1000);
    out.println("t1 lock ing");
    out.println(ClassLayout.parseInstance(a).toPrintable());//轻量锁
    sync();
    out.println("after lock");
    out.println(ClassLayout.parseInstance(a).toPrintable());//重量级锁

    System.gc();
    out.println("after gc()");
    out.println(ClassLayout.parseInstance(a).toPrintable());//无锁---gc
}

public  static  void sync() throws InterruptedException {
    synchronized (a){
        System.out.println("t1 main lock");
        out.println(ClassLayout.parseInstance(a).toPrintable());//重量锁
    }
}

结果展示如下:
在这里插入图片描述
在这里插入图片描述
上面只是展示了部分结果图片,如果需要可自行运行代码进行展示。
特别需要注意的是如果对象已经计算了hashcode就不能偏向了,示例代码如下

   Thread.sleep(5000);
    a= new A();
    a.hashCode();
    out.println("befor lock");
    out.println(ClassLayout.parseInstance(a).toPrintable());
    synchronized (a){
        out.println("lock ing");
        out.println(ClassLayout.parseInstance(a).toPrintable());
    }
    out.println("after lock");
    out.println(ClassLayout.parseInstance(a).toPrintable());
}

在这里插入图片描述
小白第一次写博客还很不熟练如有不足之处希望指出!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值