锁原理与对象头
对象头
对象头是堆中对象的头结构,它由两个部分组成,mark word和klass word
mark word的简要介绍
mark word结构图示 如图所示:
- mark word的大小为64bit,在对象的5种状态中(无锁,偏向锁,轻量级锁,重量级锁,GC标记),mark word的结构有所不同
- 在 无锁 状态时,mark word的前56bit存储对象的hashcode信息。(前25bit为未使用,后31bit存储hashcode)。
- 在 偏向锁 状态时,mark word的前54bit存储获取锁的线程相关信息.
- 在 轻量级锁 状态时,mark word的前62bit存储线程的栈的指针。
- 在 重量级锁 状态时,markword的前62bit存储一个monitor对象信息。
klassword的简要介绍
- klassword 的32位或者64位代表元数据的指针。
- klassword的大小为64bit,如果开启了指针压缩,大小为32bit。
无锁态的对象,它的hashcode以及对象头信息
先上代码,这里我们使用了openjdk的jol包,可以看到对象以及jvm相关信息
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
public static void main(String[] args) throws InterruptedException {
new JOLExample1().doHash();
//jvm的信息
// out.println(VM.current().details());
}
public void doHash(){
Base a=new Base();
out.println("before hash");
out.println(ClassLayout.parseInstance(a).toPrintable());
out.println("jvm----------"+Integer.toHexString(a.hashCode()));
out.println("after hash");
out.println(ClassLayout.parseInstance(a).toPrintable());
}
打印的无锁对象信息为
由于本机cpu采用小端模式,所以看到的hashcode在对象头中的存储顺序是高低位相反的。
延迟偏向锁以及偏向锁和轻量级锁的性能差异分析
如果一个锁不存在线程竞争,那么它是一个偏向锁。但是不同版本jdk,存在偏向锁延迟策略,所以不同版本jdk的偏向锁机制有所差异。
经测试,jdk8默认有4秒偏向延迟。jdk13默认关闭了偏向延迟,直接使用偏向锁。
我们通过代码分析下,对象在不同阶段的锁类型以及对应的运行时间。
public class CompareLock {
static Base base=new Base();
public static void main(String[] args) throws InterruptedException {
out.println("before lock");
out.println(ClassLayout.parseInstance(base).toPrintable());
TimeUnit.SECONDS.sleep(1);
testSpeed();
out.println("after lock");
out.println(ClassLayout.parseInstance(base).toPrintable());
}
public static void testSpeed() {
long stard = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
synchronized (base) {
if (i==0){
err.println("start locking 0");
out.println(ClassLayout.parseInstance(base).toPrintable());
}
if (i==200000){
err.println(" locking 200000");
out.println(ClassLayout.parseInstance(base).toPrintable());
}
if