上一篇通过构建金字塔结构,来从不同的角度,由浅入深的对synchronized关键字做了介绍,

快速跳转:https://www.cnblogs.com/xyang/p/11631866.html

本文将从底层实现的各个“组件”着手,详细拆解其工作原理。

本文会分为以下4节内容:

  第一节:介绍MarkWord和LockRecord两种数据结构,该知识点是理解synchronized关键字底层原理的关键。

  第二节:分析偏向锁加锁解锁时机和过程

一.先来了解两种数据结构,你应该了解这些知识点

1.MarkWord:在锁的使用过程中会对锁对象作出相应的操作

 在HotSpot虚拟机中,Java对象在内存中存储的布局,分为三个部分:对象头,实例数据,对齐填充。

本文重点关注对象头。

对象头又划分为2或3部分,具体包括:

  1. MarkWord(后文简称MW,后续详细介绍)
  2. 类型指针:指向这个对象所属的类的元数据(klass)的指针
  3. 最后这一部分比较特殊,只有在对象是Java数组时才会存在,记录的是数组的长度。为什么要存在这个记录呢?我们知道,在普通Java对象中,我们可以通过读取对象所属类的元数据,计算出对象的大小。而数组是无法做到的,于是借助这块区域来记录。

本文重点关注MW区域

MW是一块固定大小内存区域,在32位虚拟机中是32个bit,对应的,64位虚拟机中是64个bit。本文以32位虚拟机为例分析。

我们从直观上理解,所谓的头信息,一般都是用来记载一些不易变的信息,例如在http请求头中的各种头信息。在对象头中也是如此,例如hashcode。在JVM虚拟机中为了解决存储空间开销,对象头的MW大小已经固定。那么,要存储的信息有比较多,包括且不限于:锁标志位、GC信息、锁相关信息,总大小远远超出32bit,怎么办呢?

共享存储区域,在不同的时刻,根据需求存储需要的信息。

请参考下图:

锁类型

25bit

4bit

1bit

2bit

 

23bit

2bit

是否偏向锁

锁标志位

无锁

对象hashcode

分代年龄

0

01

偏向锁

线程ID

epoch

分代年龄

1

01

轻量级锁

指向栈中锁记录的指针

00

重量级锁

指向互斥量

10

GC标记

11

 

说明:两个标志位最多只能标识4个状态,那么剩下一个怎么办?共享。无锁和偏向锁共享01状态,他们两个的区分