设为首页 加入收藏

TOP

【开发宝典】Java并发系列教程(一)
2023-07-26 08:15:57 】 浏览:133
Tags:Java

作者:京东零售 刘跃明

Monitor概念

Java对象的内存布局

对象除了我们自定义的一些属性外,还有其它数据,在内存中可以分为三个区域:对象头、实例数据、对齐填充,这三个区域组成起来才是一个完整的对象。

对象头:在JVM中需要大量存储对象,存储时为了实现一些额外的功能,需要在对象中添加一些标记字段用于增强对象功能,这些标记字段组成了对象头。

实例数据:存放类的属性数据信息,包括父类的属性信息。

对齐填充:由于虚拟机要求对象其实地址必须是8字节的整数倍,需要存在填充区域以满足8字节的整数倍,填充数据不是必须存在的,仅仅是为了字节对齐。

图1

Java对象头

JVM中对象头的方式有以下两种(以32位虚拟机为例):

普通对象

Object Header (64 bits)
Mark Word (32 bits) Klass Word (32 bits)

数组对象

Object Header (96 bits)
Mark Word(32bits) Klass Word(32bits) array length(32bits)

Mark Word

这部分主要用来存储对象自身的运行数据,如hashcode、gc分带年龄等,Mark Word的位长度为JVM的一个Word大小,也就是说32位JVM的Mark Word为32位,64位JVM为64位。为了让一个字大小存储更多的信息,JVM将字的最低两个位设置为标记位,不同标记位下的Mark Word示意如下:

Mark Word (32 bits) State
identity_hashcode:25 age:4 biased_lock:1 lock:2 Normal
thread:23 epoch:2 age:4 biased_lock:1 lock:2 Biased
ptr_to_lock_record:30 lock:2 LightweightLocked
ptr_to_heavyweight_monitor:30 lock:2 HeavyweightLocked
lock:2 Marked for GC

其中各部分的含义如下:

lock: 2位的锁状态标记位,该标记的值不同,整个Mark Word表示的含义不同。

biased_lock lock 状态
0 01 无锁
1 01 偏向锁
0 00 轻量级锁
0 10 重量级锁
0 11 GC标记

biased_lock: 对象是否启用偏向锁标记,只占1个二进制位,为1时表示对象启用偏向锁,为0时表示对象没有偏向锁。

age: 4位的Java对象年龄,在GC中,如果对象再Survivor区复制一次,年龄增加1,当对象达到设定的阈值时,将会晋升到老年代,默认情况下,并行GC的年龄阈值为15,并发GC的年龄阈值为6,由于age只有4位,所以最大值为15,这就是-XX:MaxTenuringThreshold选项最大值为15的原因。

identity_hashcode: 25位的对象表示Hash码,采用延迟加载技术,调用方法System.idenHashcode()计算,并会将结果写到该对象头中,当对象被锁定时,该值会移动到管程Monitor中。

thread: 持有偏向锁的线程ID。

epoch: 偏向时间戳。

ptr_to_lock_record: 指向栈中锁记录的指针。

ptr_to_heavyweight_monitor: 指向管程Monitor的指针。

Klass Word

这一部分用于存储对象的类型指针,该指针指向它的类元数据,JVM通过这个指针确定对象是哪个类的实例,该指针的位长度为JVM的一个字大小,即32位的JVM为32位,64位的JVM为64位。

array length

如果对象是一个数组,那么对象头还需要有额外的空间用于存储数组的长度,这部分数据的长度也随着JVM架构的不同而不同:32位的JVM长度为32位,64位JVM则为64位。

Monitor原理

Monitor被翻译为监视器管程

每个Java对象都可以关联一个Monitor对象,如果使用synchronized给对象上锁(重量级)之后,该对象头的Mark Word中就被设置指向Monitor对象的指针。

Monitor结构如下:

图2

?刚开始Monitor中Owner为null

?当Thread-2执行synchronized(obj)就会将Monitor的所有者Owner置为Thread-2,Monitor中只能有一个Owner

?在Thread-2上锁的过程中,如果Thread-3、Thread-4、Thread-5也来执行synchronized(obj),就会进入EntryList BLOCKED

?Thread-2执行完同步代码块的内容,然后唤醒EntryList中等待的线程来竞争锁,竞争是非公平的,也就是先进并非先获取锁

?图2中WaitSet中的Thread-0、Thread-1是之前获得过锁,但条件不满足进入WAITING状态的线程,后面讲wait-notify时会分析

注意:

?synchronized必须是进入同一个对象的Monitor才有上述的效果

?不加synchronized的对象不会关联监视器,不遵从以上规则

synchronized原理

static final Object lock = new Object();
static int counter = 0;

public static void main(String[] args) {
    synchronized (lock) {
        counter++;
    }
}

对应的字节码为:

public static main([Ljava/lang/String;)V

TRYCATCHBLOCK L0 L1 L2 null

TRYCATCHBLOCK L2 L3 L2 null

L4

LINENUMBER 6 L4

GETSTATIC MyClass03.lock : Ljava/lang/Object;

DUP

ASTORE 1

MONITORENTER //注释1

L0

LINENUMBER 7 L0

GETSTATIC MyClass03.counter : I

ICONST_1

IADD

PUTSTATIC MyClass03.counter : I

L5

LINENUMBER 8 L5

ALOAD 1

MONITOREXIT //注释2

L1

GOTO L6

L2

FRAME FULL [[Ljava/lang/String; java/lang/Object] [java/lang/Throwable]

ASTORE 2

ALOAD 1

MONITOREXIT //注释3

L3

ALOAD 2

ATHROW

L6

LINENUMBER 9 L6

FRAME CHOP 1

RETURN

L7

LOCALVARIABLE args [Ljava/lang/String; L4 L7 0

MAXSTACK = 2

MAXL

首页 上一页 1 2 3 4 5 6 7 下一页 尾页 1/8/8
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇RabbitMQ-消息中间键 下一篇如何理解spring框架中的依赖注入..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目