java中的Identity hashcode带来的偏向锁膨胀

注意:看该篇文章之前您需要了解java对象头

首先介绍一个工具,能查看java对象头信息

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.8</version>
</dependency>

identity hashcode:如果我们没有重写默认的hashcode方法,默认的hashcode计算出的就是identity hashcode,这个值是被存储在对象头中的,如果重写之后,就不能叫identity hashcode了,计算出的值也不会存储在对象头中。

下文所说的hashcode都是identity hashcode

我们知道java对象头保存了一个对象的非常多的信息。

1.非数组对象的对象头中保存的是Mark Word和执行类源信息的指针

2.数组对象除了上述两个信息之外还有额外的一个数组长度信息。

Mark Word中保存的都是一个java对象所必须的信息,比如分代年龄等,identity hashcode等。

无锁状态下这些数据都是存储在对象头中的,但是当出现锁之后这行数据信息可能会发生变化,就比如轻量级锁下会将对象的Mark Word利用CAS替换到栈帧中用于记录锁记录的空间中,然后对象头中原有的位置变成了指向锁记录的指针。重量级锁也类似,不过他指向的是一个monitor对象,也能记录下原来的hashcode和分代年龄等。关键就是在于,原本存储Mark Word的位置被指针占据了,轻量级和重量级锁都会找个位置存放原有信息。但是偏向锁没有地方来存原来的位置了,所以如果你一个对象计算了hashcode之后,没地方放了怎么办,这就是hashcode与轻量级锁的冲突问题,一个对象如果计算了hashcode之后,锁就会膨胀,不能再做为偏向锁。

测试环境jdk1.8

一个简单的类

public class A {
    boolean flag = false;
    int a = 3;

}
public static void main(String[] args) throws InterruptedException {
    // 需要sleep一段时间,因为java对于偏向锁的启动是在启动几秒之后才激活。
    // 因为jvm启动的过程中会有大量的同步块,且这些同步块都有竞争,如果一启动就启动
    // 偏向锁,会出现很多没有必要的锁撤销
    Thread.sleep(5000);
    A a = new A();
    // 未出现任何获取锁的时候
    System.out.println(ClassLayout.parseInstance(a).toPrintable());
    synchronized (a){
        // 获取一次锁之后
        System.out.println(ClassLayout.parseInstance(a).toPrintable());
    }
    // 输出hashcode
    System.out.println(a.hashCode());
    // 计算了hashcode之后
    System.out.println(ClassLayout.parseInstance(a).toPrintable());
    synchronized (a){
        // 再次获取锁
        System.out.println(ClassLayout.parseInstance(a).toPrintable());
    }
}

输出1

测试环境是windows,所以数据的存储是以小端模式,101可以看出这时候的锁状态是偏向锁,但是并没有偏向的threadId,因为还没有线程获取过锁。此时是匿名偏向锁。

输出2

这时候出线程获取了一次锁,threadId出现了值。

 输出3

计算了hascode之后,大家可以计算一下输出的hashcode与存储的值是否一致,注意,小端模式。这时候发现偏向锁的标志位已经为0了,虽然锁标志位还是01,但是他进行不能作为偏向锁了,就导致至少升级为轻量级锁了。

输出4

这时候看,代码中虽然没有任何的线程竞争,但是我们的锁还是变成了轻量级锁,就是因为hashcode带来的锁膨胀的问题 

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值