对象头与锁与synchronized简述

对象头与锁与synchronized

1、对象有多大

  1. 下述代码中o对象有多大?

    Object o = new Object();
    

    我们知道一个对象是由对象头、实例数据与对齐填充三部分组成。

    1.  对象头:
        1.  markword:hashcode、锁状态、偏向线程ID、分代年龄等
        2.  类型指针:指向对象的.class对象
    2.  实例数据:对象中定义的实例变量
    3.  对齐填充:将对象大小补齐至8的整数倍
    

    当然o这个对象自然也是由这三部分组成。那么想知道o对象有多大自然要知道每一部分有多大。

    1.  对象头
        1.  markword:8字节
        2.  类型指针:
            ​		关闭指针压缩->8字节
            ​		开启指针压缩->4字节
            
    2.  实例数据:Object对象没有实例数据即大小为0字节
    
    3.  对齐填充:根据对象头+实例数据的大小进行填充
    
    4.	总结:
    	1.  开启压缩的情况下:8+4+4=16->markword+类型指针+对齐填充
    	2.  关闭压缩的情况下:8+8=16->markword+类型指针
    

    测试代码见附录1

    现在我们知道了对象的结构与对象的大小,那么对象与锁又有什么关系呢?

2、对象与锁

1、简述

​ 锁有不同的分类。分别是:无锁态、偏向锁、轻量级锁 (自旋锁,自适应自旋)、重量级锁。(这里只需要了解有多少种不同的锁分类即可,不要刻板的认为new出来的对象下一步会升级为偏向锁。)锁的相关信息必然是要被记录的而记录的载体正是对象的对象头中的markword。此外由于存储空间的有限,为了节省空间,提高空间利用率我们将markword这8个字节根据不同的锁状态划分成了不同的结构。其中锁状态与markword的关系入下图所示。

在这里插入图片描述

2、锁概述

1、无锁态

​ 对于jkd1.8来说一个对象new出来默认是无锁态的。其markword中存储了hashcode、分代年龄、偏向锁位、锁标志位。其中当我们调用hashcode方法后对象中才会有hashcode的数据。当其被加锁后则变为轻量锁。

hashcode测试代码见附录2

无锁态升级轻量锁测试代码见附录3

2、偏向锁

​ 偏向锁是对锁的一种优化,在JDK11中new出来的对象默认是偏向锁。其分为匿名偏向锁与偏向锁。当一个对象没有被锁住时便是匿名偏向锁。如果被锁住那么,就会在对象的markword中就会记录下当前线程的指针。如果在运行时此锁没有被争夺那么持有偏向锁的线程就不用进行同步。

3、轻量锁

​ 轻量级锁又叫自旋锁,它通过自旋的方式(CAS)来切换锁的所有者,当自旋的线程较多时会升级为重量锁。

CAS:在改变数据时先拿取数据变量a的值E,然后计算出V,再用E和a的值N进行比较要是相等则更新数值不相等则 重新读取数据再计算。

​ ABA问题:线程1先读取的变量a的值E,然后计算出V,在此期间线程2对变量a进行了加1与减1操作。此时线程1 无法得知a的值发生过变化,这就叫ABA问题。当然我们只需要给数值加上一个版本号就可以解决这个问题。
在这里插入图片描述

4、重量锁

​ 重量锁由操作系统实现。会导致由内核态转为用户态,消耗更多的资源。当对象升级为重量锁时争夺的线程进入队列进行等待。

3、锁实现

​ 1、java代码实现:synchronized

​ 2、字节码:monitorenter monitorexit

​ 3、运行时锁自动升级

​ 3、汇编:lock comxchg

4、锁升级

1、基本路线一:初始为偏向锁

​ 匿名偏向锁->偏向锁->轻量锁->重量锁

​ 1、初始状态下为偏向锁

​ 2、对象被锁住时进入偏向锁状态

​ 3、当对象被争夺时进入轻量锁状态

​ 4、当竞争比较激烈时进入重量锁状态

2、基本路线二:初始为无锁态

​ new->轻量锁->重量锁

​ 1、初始状态为无锁态

​ 2、当对象被争夺时进入轻量锁状态

​ 3、当竞争比较激烈时进入重量锁状态

在这里插入图片描述

5、synchronized的使用

synchronized的使用

附录

前置任务:加载对应工具类包

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
        <dependency>
            <groupId>org.openjdk.jol</groupId>
            <artifactId>jol-core</artifactId>
            <version>0.9</version>
        </dependency>
    </dependencies>

附录1:对象头大小

    public static void main(String[] args) throws InterruptedException {
        Object o = new Object();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }

附录2:对象hashcode

    public static void main(String[] args) throws InterruptedException {
        Object o = new Object();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
        o.hashCode();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }

附录3:无锁态升级轻量锁

    public static void main(String[] args) throws InterruptedException {
        Object o = new Object();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
        synchronized (o) {
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
        }
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值