java对象结构与Mark Word字段和锁的关系

617 阅读3分钟

java对象结构

    我们都知道在线程访问临界区代码块的时候,为了保证代码的原子性,从而加上像synchronized等关键字来避免出现线程并发访问的时候造成的线程安全问题,当线程进入含有synchronized关键字来修饰的代码块也好同步方法也好,我们就称这个线程获取到了一把锁,有了这把锁就可以访问临界区资源和代码块,等执行完以后,释放这把锁,让别的线程来获取。
但是这把锁是什么?来源哪里?请看以下内容:

这把锁是什么?

在java中在每个对象中都有一把锁,可以称为内置锁,或者对象锁

synchronized(syncObject){

}

使用如上的代码就相当于获取了syncObject同步对象的锁

这把锁来源哪里?

那么这把锁在对象里的什么位置呢?或者说java对象的结构是什么样子呢?
如图所示:

image.png
在图中可知java对象的实例在堆上,java对象可以分为三部分:
1.对象头
在对象头中又包含了三个字段:
(1)Mark Word(标记字):用于存储自身运行时的数据,比如GC标志位,哈希码,锁状态等信 息,由此可知锁的信息存放在这个字段中
(2)Class Pointer(类对象指针):用于存放方法区Class对象的地址,JVM通过这个指针来确定这个对象是那个类的实例
(3)Array Length(数组长度):如果对象是一个java数组这个字段是必须存在的,是一个可选字段,用于记录数组的长度

2.对象体
对象体包含对象的实例变量(成员变量),用于成员属性值,包括父类的成员属性值

3.对齐字节
是用来保证Java对象所占内存字节数为8的倍数,对象头本身是8的倍数,当对象的实例变量数据不是8的倍数时,便需要填充数据来保证8字节的对齐,相当于加入指定的字节数来保证对象所占的内存为8字节的倍数

关于Mark Word的结构信息

    java的对象锁存放在对象结构中,并且存放于对象头Mark Word字段中,Java内置锁的状态总共有4种,级别由低到高依次为:无锁偏向锁轻量级锁重量级锁,在jdk1.6之前java的对象锁是一个重量级锁,但是他的性能比较低,在jdk1.8之后JVM对synchronized的实现进行了优化,引入了偏向锁和轻量级锁,并且4种状态会随着竞争的情况逐渐升级,并且只能升级锁,不能降低锁的级别

在32位虚拟机中Mark World的大小就是32位,它的结构为:

image.png

在64位虚拟机中Mark World的大小就是64位,它的结构为:

image.png

关于64位Mark Word构成:
1.lock:锁状态标记位,占两个二进制位,该标记的值不同,整个Mark Word表示的含义就不同
2.biased_lock:对象是否启用偏向锁标记,只占1个二进制位。为1时表示对象启用偏向锁,为0时表示对象没有偏向锁
lock和biased_lock两个标记位组合在一起共同表示Object实例处于什么样的锁状态:

image.png
3.age:4位的Java对象分代年龄
4.identity_hashcode:31位的对象标识HashCode
5.thread:54位的线程ID值为持有偏向锁的线程ID
6.epoch:偏向时间戳
7.ptr_to_lock_record:占62位,在轻量级锁的状态下指向栈帧中锁记录的指针
8.ptr_to_heavyweight_monitor:占62位,在重量级锁的状态下指向对象监视器的指针

以上内容基于java高并发核心编程