java 虚拟机对锁对优化

Java对象头(不用记内容,只需要知道,对象头里面,会保存一些信息)

锁存在Java对象头里。如果对象是数组类型,则虚拟机用3个Word(字宽)存储对象头,如果对象是非数组类型,则用2字宽存储对象头。在32位虚拟机中,一字宽等于四字节,即32bit。(下面这个表格讲的很清楚)

长度

内容

说明

32/64bit

Mark Word

存储对象的hashCode或锁信息等。

32/64bit

Class Metadata Address

存储到对象类型数据的指针

32/64bit

Array length

数组的长度(如果当前对象是数组)

Java对象头里的Mark Word里默认存储对象的HashCode,分代年龄和锁标记位。32位JVM的Mark Word的默认存储结构如下:

25 bit

4bit

1bit

是否是偏向锁

2bit

锁标志位

无锁状态

对象的hashCode

对象分代年龄

0

01

在运行期间Mark Word里存储的数据会随着锁标志位的变化而变化。Mark Word可能变化为存储以下4种数据: 

锁状态

25 bit

4bit

1bit

2bit

23bit

2bit

是否是偏向锁

锁标志位

轻量级锁

指向栈中锁记录的指针

00

重量级锁

指向互斥量(重量级锁)的指针

10

GC标记

11

偏向锁

线程ID

Epoch

对象分代年龄

1

01

在64位虚拟机下,Mark Word是64bit大小的,其存储结构如下:  

锁状态

25bit

31bit

1bit

4bit

1bit

2bit

cms_free

分代年龄

偏向锁

锁标志位

无锁

unused

hashCode

0

01

偏向锁

ThreadID(54bit) Epoch(2bit)

1

01

偏向锁,简单的讲,就是在锁对象的对象头中有个ThreaddId字段,这个字段如果是空的,
第一次获取锁的时候,就将自身的ThreadId写入到锁的ThreadId字段内,将锁头内的是否偏向锁的状态位置1.
这样下次获取锁的时候,直接检查ThreadId是否和自身线程Id一致,如果一致,则认为当前线程已经获取了锁,因此不需再次获取锁,
略过了轻量级锁和重量级锁的加锁阶段。提高了效率

流程是这样的 偏向锁->轻量级锁->重量级锁
第一步,检查MarkWord里面是不是放的自己的ThreadId ,如果是,表示当前线程是处于 “偏向锁”
第二步,如果MarkWord不是自己的ThreadId,锁升级,这时候,用CAS来执行切换,新的线程根据MarkWord里面现有的ThreadId,通知之前线程暂停,
之前线程将Markword的内容置为空。
第三步,两个线程都把对象的HashCode复制到自己新建的用于存储锁的记录空间,接着开始通过CAS操作,
把共享对象的MarKword的内容修改为自己新建的记录空间的地址的方式竞争MarkWord,
第四步,第三步中成功执行CAS的获得资源,失败的则进入自旋
第五步,自旋的线程在自旋过程中,成功获得资源(即之前获的资源的线程执行完成并释放了共享资源),则整个状态依然处于 轻量级锁的状态,如果自旋失败
第六步,进入重量级锁的状态,这个时候,自旋的线程进行阻塞,等待之前线程执行完成并唤醒自己

  • 锁消除
     锁消除是一种更彻底的锁优化,Java虚拟机在Jit编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁的时间,如果不可能存在竞争,为什么还要加锁呢?这是因为咋Java软件开发过程中,我们必然会使用一些JDK的内置API,比如StringBuffer,Vector等,你在使用的时候,也许根本不会考虑这些对象内部是如何实现的,但是真实环境中,缺不存在竞争,如果虚拟机检测到这种情况,就会将这些无用的锁操作去除,
复制代码
public String[] createStrings() {
    Vector<String> v = new Vector<>();
    for (int i = 0; i < 100; i++) {
        v.add(Integer.toString(i));
    }
    return v.toArray(new String[]{});
}
复制代码
     锁消除涉及一项关键技术为逃逸分析,所谓逃逸分析就是观察某一个变量是否会逃出某一个作用域,在本例子中,变量v显然没有逃出createStrings()方法之外,以此为基础,虚拟机才可以大胆地将v内部的加锁操作去除,
     逃逸分析必须在-server模式下进行,可以使用-XX:+DoEscapeAnalysis参数打开逃逸分析.使用-XX:+EliminateLocks参数可以打开锁消除.
原文地址:https://www.cnblogs.com/sg9527/p/8022341.html