对象由多部分构成的,对象头,属性字段、补齐区域等。所谓补齐区域是指如果对象总大小不是4字节的整数倍,会填充上一段内存地址使之成为整数倍。

后面两个很好理解,今天我主要想总结一下对象头:

对象头这部分在对象的最前端,包含两部分或者三部分:Mark Words、Klass Words,如果对象是一个数组,那么还可能包含第三部分:数组的长度。


Klass Word里面存的是一个地址,占32位或64位,是一个指向当前对象所属于的类的地址,可以通过这个地址获取到它的元数据信息。


Mark Word需要重点说一下,这里面主要包含对象的哈希值、年龄分代、锁标志位等,大小为32位或64位

当对象处于不同的锁状态时,它的Mark Word里的东西会被替换成不同东西,如下表所示:

1、对象未加锁的时候,lock标志位为01,包含哈希值、年龄分代和偏向锁标志位等,此时偏向锁标志位为0;

2、当对象被施加偏向锁时,哈希值和一部分无用内存会转化为锁主人的线程信息,以及加锁的时间戳epoch,此时lock标志位没变,偏向锁为1,也就是说,偏向锁和lock标志位共同决定是否偏向锁状态。

偏向锁的加锁步骤:

  • Load-and-test,也就是简单判断一下当前线程id是否与Markword当中的线程id是否一致.
  • 如果一致,则说明此线程已经成功获得了锁,继续执行下面的代码.
  • 如果不一致,则要检查一下对象是否还是可偏向,即“是否偏向锁”标志位的值。
  • 如果还未偏向,则利用CAS操作来竞争锁,也即是第一次获取锁时的操作。

3、当发生锁竞争时,偏向锁会变为轻量级锁,这时需要先将偏向锁进行锁撤销,这一步骤也会消耗不少的性能,轻量级锁的Mark Word中,lock标志位为00,其余内容被替换为一个指针,指向了栈里面的锁记录。

锁撤销的过程如下:

  • 在一个安全点停止拥有锁的线程。
  • 遍历线程栈,如果存在锁记录的话,需要修复锁记录和Markword,使其变成无锁状态。
  • 唤醒当前线程,将当前锁升级成轻量级锁。

所以,如果某些同步代码块大多数情况下都是有两个及以上的线程竞争的话,那么偏向锁就会是一种累赘,对于这种情况,我们可以一开始就把偏向锁这个默认功能给关闭

轻量级锁的加锁步骤:

  • 线程在自己的栈桢中创建锁记录LockRecord。
  • 将锁对象的对象头中的MarkWord复制到线程的刚刚创建的锁记录中。
  • 将锁记录中的Owner指针指向锁对象。
  • 将锁对象的对象头的MarkWord替换为指向锁记录的指针。

轻量级锁主要有两种:自旋锁和自适应自旋锁。自旋锁会导致空耗CPU且很可能锁不公平;自适应是指根据上一次该线程是否成功或者多久获取过该锁设置旋转次数,若上次失败很可能直接进入重量级锁

4、如果竞争线程增多,锁继续膨胀,变为重量级锁,也是互斥锁,即synchronized,其lock标志位为10,Mark Word其余内容被替换为一个指向对象监视器Monitor的指针。

特殊的是,如果此对象已经被GC标记过,lock会变为11,不含其余内容。


Monitor对象

每个对象都有一个Monitor对象相关联,Monitor对象中记录了持有锁的线程信息、等待队列等。Monitor对象包含以下三个字段:

  • _owner 记录当前持有锁的线程
  • _EntryList 是一个队列,记录所有阻塞等待锁的线程
  • _WaitSet 也是一个队列,记录调用 wait() 方法并还未被通知的线程

当线程持有锁的时候,线程id等信息会拷贝进owner字段,其余线程会进入阻塞队列entrylist,当持有锁的线程执行wait方法,会立即释放锁进入waitset,当线程释放锁的时候,owner会被置空,公平锁条件下,entrylist中的线程会竞争锁,竞争成功的线程id会写入owner,其余线程继续在entrylist中等待。


Monitor与Synchronized

对于Synchronized的同步代码块,JVM会在进入代码块之前加上monitorenter ,如果进入monitor成功,线程便获取了锁,一个对象的monitor同一时刻只能被一个线程锁占有;

对于同步方法,JVM会讲方法设置 ACC_SYNCHRONIZED 标志,调用的时候 JVM 根据这个标志判断是否是同步方法。

采用Synchronized给对象加锁会使线程阻塞,因而会造成线程状态的切换,而线程状态的切换必须要操作系统来执行,因此需要将用户态切换为内核态,这个切换的过程是十分耗时的都需要操作系统来帮忙,有可能比用户执行代码的时间还要长。


Synchronized是JVM级别的锁,它在不断被优化着,从目前来看Synchronized已经远没有以前那么“重”了,也大概就是JUC包源码(如ConcurrentHashMap)中大量使用Synchronized的原因把

Java对象头与锁的更多相关文章

  1. 并发王者课-青铜5:一探究竟-如何从synchronized理解Java对象头中的锁

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

  2. 015-线程同步-synchronized几种加锁方式、Java对象头和Monitor、Mutex Lock、JDK1.6对synchronized锁的优化实现

    一.synchronized概述基本使用 为确保共享变量不会出现并发问题,通常会对修改共享变量的代码块用synchronized加锁,确保同一时刻只有一个线程在修改共享变量,从而避免并发问题. syn ...

  3. java对象头信息和三种锁的性能对比

    java头的信息分析 首先为什么我要去研究java的对象头呢? 这里截取一张hotspot的源码当中的注释 这张图换成可读的表格如下 |-------------------------------- ...

  4. 盘一盘 synchronized (一)—— 从打印Java对象头说起

    Java对象头的组成 Java对象的对象头由 mark word 和  klass pointer 两部分组成, mark word存储了同步状态.标识.hashcode.GC状态等等. klass  ...

  5. 探究java对象头

    探究java对象头 研究java对象头,我这里先截取Hotspot中关于对象头的描述,本文研究基于64-bit HotSpot VM 文件路径 openjdk-jdk8u-jdk8u\hotspot\ ...

  6. JVM源码分析之Java对象头实现

    原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 “365篇原创计划”第十一篇. 今天呢!灯塔君跟大家讲: JVM源码分析之Java对象头实现 HotSpot虚拟机中,对象在内存中的布局分为三 ...

  7. JAVA对象头详解(含32位虚拟机与64位虚拟机)

    为什么要学习Java对象头 学习Java对象头主要是为了解synchronized底层原理,synchronized锁升级过程,Java并发编程等. JAVA对象头 由于Java面向对象的思想,在JV ...

  8. jvm源码解析java对象头

    认真学习过java的同学应该都知道,java对象由三个部分组成:对象头,实例数据,对齐填充,这三大部分扛起了java的大旗对象,实例数据其实就是我们对象中的数据,对齐填充是由于为了规则分配内存空间,j ...

  9. Java 对象头那点事

    概览 对象头 存放:关于堆对象的布局.类型.GC状态.同步状态和标识哈希码的基本信息.Java对象和vm内部对象都有一个共同的对象头格式. (后面做详细介绍) 实例数据 存放:类的数据信息,父类的信息 ...

随机推荐

  1. WPF 之 DataTemplate 实例(摘抄)

     

  2. IE下form表单密码输入框可以输入中文问题

    今天遇到了一个问题: 在IE浏览器登录界面,密码输入框,切换到中文输入法,竟然可以输入中文,已经设置过了input的type="password". 解决方法: 可以给input设 ...

  3. Java语法格式

    任何一种语言都有自己的语法规则,Java也一样,既然是规则,那么知道其如何使用就可以了. 代码都定义在类中,类由class来定义,区分 public class  和  class; 代码严格区分大小 ...

  4. Python--day23--初识面向对象复习

    面向对象编程是大程序编程思想:

  5. 2019-8-30-C#-反射调用私有事件

    title author date CreateTime categories C# 反射调用私有事件 lindexi 2019-08-30 08:52:57 +0800 2018-09-19 20: ...

  6. Codeforces Round #561 (Div. 2)

    C. A Tale of Two Lands 题意: 给出 n 个数,问有多少点对(x,y)满足 |x-y| ≤ |x|,|y| ≤ |x+y|: (x,y) 和 (y,x) 表示一种答案: 题解: ...

  7. P1009 字符三角形

    题目描述 输入一个字符c,按照阳历输出的格式输出由该字符组成的一个字符三角形. 输入格式 输入包含一个字符c. 输出格式 输出由该字符c组成的字符三角形. 样例输入 A 样例输出 A AAA AAAA ...

  8. 2018-8-10-win10-uwp-萤火虫效果

    title author date CreateTime categories win10 uwp 萤火虫效果 lindexi 2018-08-10 19:16:51 +0800 2018-2-13 ...

  9. VisualStudio 断点调试详解

    本文详细告诉大家 VisualStudio 断点调试的功能和使用方法,本文使用的是最新 VisualStudio2019 的功能,也许在你看到这篇博客的时候这个版本已经过时 本文将会按照从简单到复杂, ...

  10. Python4_数据库相关操作

    ====================================================== 参考链接: PyCharm IDE 链接sqlite.建表.添加.查询数据:https:/ ...