关于锁升级,经历过hashcode后的结果

@TOC

一、锁升级问题

package com.woniuxy.synchronizedupgrade;

import org.openjdk.jol.info.ClassLayout;

class C{
    int a=0;
    int d=0;
    static String b="123";
}
/**
 * Auther: mayuhang  <br/>
 * Date: 2020/7/8:22:21  <br/>
 * Description:
 */
public class  ObjectUpGrade {
    public static void main(String[] args) throws InterruptedException {
        //放在延时前,JVM未开启偏向锁,创建的c1对象,会出现一个问题,它会直接从无锁升级为轻量级锁
        C c1 = new C();
        System.out.println("启动后,c1:无锁" + ClassLayout.parseInstance(c1).toPrintable());
        //预留4s,等待开启偏向锁功能 或者使用命令
        //vm参数: -XX:+UseBiasedLocking开启偏向锁
        //-XX:BiasedLockingStartupDelay=0 关闭偏向锁4秒延迟
        Thread.sleep(4001);
        synchronized (c1) {
            System.out.println("c1第一次加锁后:轻量级锁" + ClassLayout.parseInstance(c1).toPrintable());
        }
        //4秒后的对象,就可以有偏向锁状态,如果没有加锁,
        //则直接是匿名偏向,也就是没有线程竞争锁状态,无线程id信息
        C c = new C();
        System.out.println("VM开启偏向锁后:c是匿名偏向锁" + ClassLayout.parseInstance(c).toPrintable());
        synchronized (c) {
            //对c进行加锁后,出现了线程获取c的Monitor,则会修改为偏向锁
            System.out.println("c第一次加锁后:偏向锁" + ClassLayout.parseInstance(c).toPrintable());
        }
}

打印结果如下:参考下图,判断对象的锁状态
在这里插入图片描述

启动后,c1:无锁com.woniuxy.synchronizedupgrade.C object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000`001`锁状态位 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4    int C.a                                       0
     16     4    int C.d                                       0
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

c1第一次加锁后:轻量级锁com.woniuxy.synchronizedupgrade.C object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           50 f1 c6 02 (01010000 11110001 11000110 00000010) (46592336)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4    int C.a                                       0
     16     4    int C.d                                       0
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

VM开启偏向锁后:c是匿名偏向锁com.woniuxy.synchronizedupgrade.C object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4    int C.a                                       0
     16     4    int C.d                                       0
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

c第一次加锁后:偏向锁com.woniuxy.synchronizedupgrade.C object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 e8 af 02 (00000101 11101000 10101111 00000010) (45082629)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4    int C.a                                       0
     16     4    int C.d                                       0
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

根据第三版《深入理解java虚拟机》第三版13.3.
5偏向锁章节最后几段话,原文如下:

看到这里可能会发现一个问题:
当对象进入偏向状态的时候,Mark Word大部分的空间(23个比特)都用于存储持有锁的线程ID了,这部分空间占用了原有存储对 象哈希码的位置,那原来对象的哈希码怎么办呢?
在Java语言里面一个对象如果计算过哈希码,就应该一直保持该值不变(强烈推荐但不强制,因为用户可以重载hashCode()方法按自己的意愿返回哈希码),否则很多依赖对象哈希码的API都可能存在出错风险。而作为绝大多数对象哈希码来源的Object::hashCode()方法,返回的是对象的一致性哈希码(Identity> Hash> Code),这个值是能强制保证不变的,它通过在对象头中存储计算结果来保证第一次计算之后,再次调用该方法取到的哈希码值永远不会再发生改变。因此,当一个对象已经计算过一致性哈希码后,它就再也无法进入偏向锁状态了;而当一个对象当前正处于偏向锁状态,又收到需要计算其一致性哈希码请求时,它的偏向状态会被立即撤销,并且锁会膨胀为重量级锁。在重量级锁的实现中,对象头指向了重量级锁的位置,代表重量级锁的ObiectMonitor类里有字段可以记录非加锁状态(标志位为“01”)下的Mark
Word,其中自然可以存储原来的哈希码。
偏向锁可以提高带有同步但无竞争的程序性能,但它同样是一个带有效益权衡(TradeOff)性质的优化,也就是说它并非总是对程序运行有利。如果程序中大多数的锁都总是被多个不同的线程访问,那偏向模式就是多余的。在具体问题具体分析的前提下,有时候使用参数-XX:-UseBiasedLocking来禁止偏向锁优化反而可以提升性能"。

其中,这句话和测试结果有区别:

当一个对象当前正处于偏向锁状态,又收到需要计算其一致性哈希码请求时,它的偏向状态会被立即撤销,并且锁会膨胀为重量级锁。

测试代码如下:

package com.woniuxy.synchronizedupgrade;

import org.openjdk.jol.info.ClassLayout;

class C{
    int a=0;
    int d=0;
    static String b="123";
}
/**
 * Auther: mayuhang  <br/>
 * Date: 2020/7/8:22:21  <br/>
 * Description:
 */
public class  ObjectUpGrade {
    public static void main(String[] args) throws InterruptedException {
        //放在延时前,JVM未开启偏向锁,创建的c1对象,会出现一个问题,它会直接从无锁升级为轻量级锁
        C c1 = new C();
        System.out.println("启动后,c1:无锁" + ClassLayout.parseInstance(c1).toPrintable());
        //预留4s,等待开启偏向锁功能 或者使用命令
        //vm参数: -XX:+UseBiasedLocking开启偏向锁 -XX:BiasedLockingStartupDelay=0 关闭偏向锁4秒延迟
        Thread.sleep(4001);
        synchronized (c1) {
            System.out.println("c1第一次加锁后:轻量级锁" + ClassLayout.parseInstance(c1).toPrintable());
        }
        //4秒后的对象,就可以有偏向锁状态,如果没有加锁,则直接是匿名偏向,也就是没有线程竞争锁状态,无线程id信息
        C c = new C();
        System.out.println("VM开启偏向锁后:c是匿名偏向锁" + ClassLayout.parseInstance(c).toPrintable());
        synchronized (c) {
            //对c进行加锁后,出现了线程获取c的Monitor,则会修改为偏向锁
            System.out.println("c第一次加锁后:偏向锁" + ClassLayout.parseInstance(c).toPrintable());
        }
//      计算HashCode撤销偏向锁
        System.out.println(Integer.toHexString(c.hashCode()));
        System.out.println("计算hash后的状态:c是无锁状态" + ClassLayout.parseInstance(c).toPrintable());
        synchronized (c) {
            System.out.println("第二次加锁后:c直接升级为轻量级锁" + ClassLayout.parseInstance(c).toPrintable());
        }
        new Thread(()->{
            synchronized (c) {
                System.out.println("还未存在线程竞争:c为轻量级锁" + ClassLayout.parseInstance(c).toPrintable());
            }
        }).start();
        new Thread(()->{
            synchronized (c) {
                System.out.println("存在线程竞争:c升级为重量级锁" + ClassLayout.parseInstance(c).toPrintable());
            }
        }).start();
    }
}

结果如下:

启动后,c1:无锁com.woniuxy.synchronizedupgrade.C object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4    int C.a                                       0
     16     4    int C.d                                       0
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

c1第一次加锁后:轻量级锁com.woniuxy.synchronizedupgrade.C object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           f8 f7 7f 02 (11111000 11110111 01111111 00000010) (41940984)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4    int C.a                                       0
     16     4    int C.d                                       0
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

VM开启偏向锁后:c是匿名偏向锁com.woniuxy.synchronizedupgrade.C object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4    int C.a                                       0
     16     4    int C.d                                       0
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

c第一次加锁后:偏向锁com.woniuxy.synchronizedupgrade.C object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 e8 68 02 (00000101 11101000 01101000 00000010) (40429573)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4    int C.a                                       0
     16     4    int C.d                                       0
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

64a294a6
计算hash后的状态:c是无锁状态com.woniuxy.synchronizedupgrade.C object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 a6 94 a2 (00000001 10100110 10010100 10100010) (-1567316479)
      4     4        (object header)                           64 00 00 00 (01100100 00000000 00000000 00000000) (100)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4    int C.a                                       0
     16     4    int C.d                                       0
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

第二次加锁后:c直接升级为轻量级锁com.woniuxy.synchronizedupgrade.C object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           f8 f7 7f 02 (11111000 11110111 01111111 00000010) (41940984)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4    int C.a                                       0
     16     4    int C.d                                       0
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

还未存在线程竞争:c为轻量级锁com.woniuxy.synchronizedupgrade.C object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           20 f5 ae 21 (00100000 11110101 10101110 00100001) (565114144)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4    int C.a                                       0
     16     4    int C.d                                       0
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

存在线程竞争:c升级为重量级锁com.woniuxy.synchronizedupgrade.C object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           5a 2d b8 1c (01011010 00101101 10111000 00011100) (481832282)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4    int C.a                                       0
     16     4    int C.d                                       0
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

总结

升级状态,全部都实现了一遍。
从无锁,到匿名偏向锁,到偏向锁,到轻量级锁,到重量级锁。
如果需要根据引用的文章,测试偏向锁计算HashCode后直接升级为重量级锁,代码如下:

package com.woniuxy.synchronizedupgrade;

import org.openjdk.jol.info.ClassLayout;

class C{
    int a=0;
    int d=0;
    static String b="123";
}
/**
 * Auther: mayuhang  <br/>
 * Date: 2020/7/8:22:21  <br/>
 * Description:
 */
public class  ObjectUpGrade {
    public static void main(String[] args) throws InterruptedException {
        //放在延时前,JVM未开启偏向锁,创建的c1对象,会出现一个问题,它会直接从无锁升级为轻量级锁
        C c1 = new C();
        System.out.println("启动后,c1:无锁" + ClassLayout.parseInstance(c1).toPrintable());
        //预留4s,等待开启偏向锁功能 或者使用命令
        //vm参数: -XX:+UseBiasedLocking开启偏向锁 -XX:BiasedLockingStartupDelay=0 关闭偏向锁4秒延迟
        Thread.sleep(4001);
        synchronized (c1) {
            System.out.println("c1第一次加锁后:轻量级锁" + ClassLayout.parseInstance(c1).toPrintable());
        }
        //4秒后的对象,就可以有偏向锁状态,如果没有加锁,则直接是匿名偏向,也就是没有线程竞争锁状态,无线程id信息
        C c = new C();
        System.out.println("VM开启偏向锁后:c是匿名偏向锁" + ClassLayout.parseInstance(c).toPrintable());
        synchronized (c) {
            //对c进行加锁后,出现了线程获取c的Monitor,则会修改为偏向锁
            System.out.println("c第一次加锁后:偏向锁" + ClassLayout.parseInstance(c).toPrintable());
        }
        synchronized (c) {
            c.hashCode();
            System.out.println("第二次加锁后:计算HashCode后偏向直升重量级锁:" + ClassLayout.parseInstance(c).toPrintable());
        }
    }
}

启动后,c1:无锁com.woniuxy.synchronizedupgrade.C object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4    int C.a                                       0
     16     4    int C.d                                       0
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

c1第一次加锁后:轻量级锁com.woniuxy.synchronizedupgrade.C object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           98 f3 bf 02 (10011000 11110011 10111111 00000010) (46134168)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4    int C.a                                       0
     16     4    int C.d                                       0
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

VM开启偏向锁后:c是匿名偏向锁com.woniuxy.synchronizedupgrade.C object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4    int C.a                                       0
     16     4    int C.d                                       0
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

c第一次加锁后:偏向锁com.woniuxy.synchronizedupgrade.C object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 e8 6b 02 (00000101 11101000 01101011 00000010) (40626181)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4    int C.a                                       0
     16     4    int C.d                                       0
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

第二次加锁后:计算HashCode后偏向直升重量级锁:com.woniuxy.synchronizedupgrade.C object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           9a 45 ba 1c (10011010 01000101 10111010 00011100) (481969562)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4    int C.a                                       0
     16     4    int C.d                                       0
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值