对象头与锁与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());}}

对象头与锁与synchronized简述相关推荐

  1. 对象头、锁的四种状态、Java和处理器实现原子操作的方式(CAS、锁机制;总线锁定、缓存锁定)

    1.对象头 Java对象头里的Mark Word里默认存储对象的HashCode.分代年龄和锁标记位. 32位JVM的Mark Word的默认存储结构如下图所示: 在运行期间,Mark Word里存储 ...

  2. 青铜5:一探究竟-从synchronized理解对象头中的锁

    在前面的文章<青铜4:synchronized用法初体验>中,我们已经提到锁的概念,并指出synchronized是锁机制的一种实现.可是,这么说未免太过抽象,你可能无法直观地理解锁究竟是 ...

  3. java对象头_我的并发编程(二):java对象头以及synchronized升级过程

    一.概述 研究java对象头的目的是详细分析Java的synchronized锁的升级过程,因为synchronized在锁升级的时候,就是依赖对象头的信息来决定的.本博文针对64位的操作系统来对Ja ...

  4. Java锁的逻辑(结合对象头和ObjectMonitor)

    我们都知道在Java编程中多线程的同步使用synchronized关键字来标识,那么这个关键字在JVM底层到底是如何实现的呢. 我们先来思考一下如果我们自己实现的一个锁该怎么做呢: 首先肯定要有个标记 ...

  5. java的头怎么写_JAVA对象布局之对象头(Object Header)

    由于Java面向对象的思想,在JVM中需要大量存储对象,存储时为了实现一些额外的功能,需要在对象中添加一些标记字段用于增强对象功能 .在学习并发编程知识synchronized时,我们总是难以理解其实 ...

  6. JAVA对象布局之对象头(Object Header)

    由于Java面向对象的思想,在JVM中需要大量存储对象,存储时为了实现一些额外的功能,需要在对象中添加一些标记字段用于增强对象功能 .在学习并发编程知识synchronized时,我们总是难以理解其实 ...

  7. 64位JVM的Java对象头详解

    关注"Java艺术"一起来充电吧! 我们编写一个Java类,编译后会生成.class文件,当类加载器将class文件加载到jvm时,会生成一个Klass类型的对象(c++),称为类 ...

  8. Java多线程,锁(CAS,synchronized,AQS,ReentrantLock)

    该博客只是个人学习的笔记.如果有什么疑问或者有什么不对的都可以告诉我,目前只写了多线程和锁的部分,因为只是个人学习记录的笔记,所以写的不是很详细,里面有一些个人的见解思考供各位参考. 一.多线程 关于 ...

  9. Java中创建对象的六个步骤 细分后(new关键字)对象头详细介绍

    要看的懂对象的创建过程,首先你得有对Java虚拟机和Java基础以及JUC很是熟悉, 比如类的加载过程.CAS.多线程.JVM的GC等等 文章目录 一.创建对象的六个步骤: 二.对象头的内部结构 首先 ...

最新文章

  1. python库缺少pkg_resource_ImportError: No module named pkg_resources解决方案
  2. 信息上传服务器加速cpu处理,英特尔发布全新第二代至强可扩展处理器携手浪潮加速新型应用发展...
  3. HDU - 6082 度度熊与邪恶大魔王(背包变式)
  4. 基于迭代次数和分类准确率的两种排序
  5. 记一次iis+aspx环境下利用http参数污染绕过waf
  6. php两个数组找公共部分,PHP开发中如何查找两个数组的交集
  7. dart 替代java_Dart与Java的语法区别
  8. js时间戳转成日期格式
  9. python基础-userlist、userdict、userstring
  10. 【Opencv系列】之显示图像以及使用鼠标截取图像局部区域进行放大
  11. ios simulator android,How to open IOS Simulator in Android Studio for Flutter application
  12. Lua注册C++类及函数
  13. DWM1000 收发RXLED TXLED控制代码修改
  14. Integer与int的种种比较你知道多少?
  15. 95后频频离职,是员工本人问题?
  16. 大一计算机期末考试高数试卷,大一高数期末考试试题
  17. SpringBoot2.X 单元测试(Junit4.X) 基本配置
  18. 【屏幕适配】像素密度 分辨率 dp px的关系
  19. 与“鸡”对话的时代孤独
  20. ios10 上下黑边问题

热门文章

  1. iOS 使用 SceneKit 实现全景图
  2. Python 正则表达式 match、findall、search
  3. python批量提取word指定内容_python批量提取word内信息
  4. 511遇见安卓手机投屏支持一键转无线群控
  5. 华为手机忘记密码如何解开,有什么相关教程吗
  6. 植物大战僵尸:寻找葵花生产速度
  7. Android NFC开发详解 总结和NFC读卡实例解析
  8. element ui的双层el-dialog样式控制
  9. Windows API 函数SendMessage与PostMessage使用方法和常见的坑
  10. Unloaded branch node detected. “loadOptions“ prop is required to load its children.