JUC-05 详解Synchronized part3

在上一篇文章中我们讲了Synchronized关键字的底层实现第一部分,主要涉及JVM的指令和Monitor对象。今天我们就继续来挖掘一下 Synchronized的底层实现,围绕对象的存储结构和对象头的构成和作用进行一下解析。

本文主要围绕下面两个问题进行解析。

  1. 对象的存储结构了解吗?
  2. 对象头里有什么?作用呢?

1. JVM中对象的存储结构

我们以Hotspot为例,下图描述了Java对象实例在JVM中的存储结构。

对象头:

    1. Java对象头一般占有2个机器码(在32位虚拟机中,1个机器码等于4字节,也就是32bit,在64位虚拟机中,1个机器码是8个字节,也就是64bit)。
    2. 特殊情况,对象是数组类型,额外需要4个字节(会多占一个机器码),用来记录数组长度(因为JVM虚拟机可以通过Java对象的元数据信息确定Java对象的大小,但是无法从数组的元数据来确认数组的大小)。

Hotspot虚拟机的对象头(非数组情况下)主要包括两部分数据:

  • Mark Word(标记字段)
  • Class Pointer(类型指针)

Mark Word用于存储对象自身的运行时数据,它是实现轻量级锁和偏向锁的关键。

Class Pointer是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例,64位时8字节,开启指针压缩或者最大堆内存小于32G时为4个字节。

对象头中的MarkWord:

JVM在1.6版本以上默认开启指针压缩,所以会压缩到4个字节(原来8个字节),32bit。

markWord中储存的内容:

      • 对象哈希码、对象分代年龄
      • 指向锁记录的指针
      • 指向重量级锁的指针
      • 空,不需要记录信息
      • 偏向线程 ID、偏向时间截、对象分代年龄

我们这里简单提一下锁的四种不可逆的状态:无锁状态 -> 偏向锁状态 -> 轻量级锁状态 -> 重量级锁状态

下图是64位虚拟机在不压缩情况下的展示,也就是25bit扩充为57bit

instance data 实例数据:

在对象实例的存储结构中,对象头之后的,就是用来存放类的属性数据信息的instance data,其中包括父类的属性信息等内容。

padding 对齐填充:

存储结构中最后部分的对齐填充,主要由于虚拟机要求 对象起始地址必须是8字节的整数倍。填充数据不是必须存在的,仅仅是为了字节对齐;(比如:7个Long)

四种不可逆的状态:无锁状态 -> 偏向锁状态 -> 轻量级锁状态 -> 重量级锁状态

下表来自《Java并发编程的艺术》:

优点

缺点

适用场景

偏向锁

加锁和解锁不需要额外的消耗,和执行非同步方法比仅存在纳秒级的差距。

如果线程间存在锁竞争,会带来额外的锁撤销的消耗。

适用于只有一个线程访问同步块场景。

轻量级锁

竞争的线程不会阻塞,提高了程序的响应速度。

如果始终得不到锁竞争的线程使用自旋会消耗CPU。

追求响应时间。同步块执行速度非常快。

重量级锁

线程竞争不使用自旋,不会消耗CPU。

线程阻塞,响应时间缓慢。

追求吞吐量。同步块执行时间较长。

更多更精彩的内容请关注。

        V信公众号搜索   “程序员一棵树”。 内有相关文档原文和免费资料。
        D音搜索             “程序员一棵树”。
        B站搜索             “程序员一棵树”。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员一棵树

创作不易,感谢土豪打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值