Syn笔记--jol查看对象头

jol查看对象头来分析一波synchronize关键字加锁过程

synchronize在jdk1.5之前就是一个重量级的锁,是在jvm层面加锁的一种形式,在字节码运行的过程中被翻译成了两个指令,速度很慢。jkd1.6开始对synchronize进行了非常多的优化,使sync有了一个锁升级机制,可以让sync在不同的场景下加不同的锁,大大提升了sync的效率。sync一共有三种锁状态:偏向锁、轻量级锁、重量级锁。下面通过查看class对象头的方式来查看这几个锁状态是怎么表现的。

import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;
import static java.lang.System.out;

public class JOLExample1 {
    public static void main(String[] args) throws Exception {
        A a = new A();
        out.println(VM.current().details());
        out.println(ClassLayout.parseInstance(a).toPrintable());
    }
}
# Running 64-bit HotSpot VM.
# Using compressed oop with 3-bit shift.
# Using compressed klass with 3-bit shift.
# Objects are 8 bytes aligned.
# Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]

com.wave.test.A object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

通过查看value可以发现没有加锁的对象的状态是01(无锁状态)。

偏向锁在对象头上有一个bit用来标识偏向状态,所以如果是101就是偏向锁

import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;
import static java.lang.System.out;
//没有竞争,理论上是偏向锁
public class JOLExample2 {
    static A a;
    public static void main(String[] args)throws Exception{
        a = new A();
        out.println("befre lock");
        out.println(ClassLayout.parseInstance(a).toPrintable());
        sync();
        out.println("after lock");
        out.println(ClassLayout.parseInstance(a).toPrintable());
    }
    public static void sync() throws InterruptedException {
        synchronized (a){
            System.out.println("我也不知道要打印什么");
        }
    }
}

神奇的发现加了锁还是01,这里是因为偏向锁会有一个4s的延迟,修改虚拟机参数或者睡眠5s就可以看到101了(XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0)

befre lock
com.wave.test.A object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

我也不知道要打印什么
after lock
com.wave.test.A object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

一个对象如果被两个线程加了锁,那就会变成轻量级锁,如果被两个线程竞争了,就会变成重量级锁

//轻量级锁
public class JOLExample3 {
    static A a;
    public static void main(String[] args)throws Exception{
        //Thread.sleep(5000);
        a = new A();
        out.println("befre lock");
         new Thread(()->{
            sync();
        }).start();
        Thread.sleep(10000);//如果减小这个值,让两个线程发生竞争,就会产生重量级锁
        out.println("after lock");
        //out.println(ClassLayout.parseInstance(a).toPrintable());
        sync();

    }
    public static void sync() {
        synchronized (a){
            try {
                out.println(ClassLayout.parseInstance(a).toPrintable());
            }catch (Exception e){
            }

        }
    }
}

你可能感兴趣的:(并发)