锁的升级过程——偏向锁、轻量级锁、重量级锁

对象的内存布局
  1. 对象头(Header)
  2. 实例数据(Instance Data)
  3. 对其填充(Padding)
对象头
  1. Mark Word:存储对象的hashcode、分代年龄、锁信息等
  2. Class Metadata Address(类型指针):存储到对象类型数据的指针
  3. Array length:数组长度(数组特有)
实例数据

对象真正存储的有效信息,继承自父类及子类所定义的所定义的各种类型的字段内容。

对齐填充

起占位符的作用,对象的大小必须为8字节的整倍数,对象头部分正好为8字节的倍数(1倍或2倍),当对象实例数据部分没有对其时,需使用对其填充来补全。


64位虚拟机下的Mark Word(64bit)

锁的升级过程——偏向锁、轻量级锁、重量级锁_第1张图片

<dependency>
    <groupId>org.openjdk.jolgroupId>
    <artifactId>jol-coreartifactId>
    <version>0.11version>
dependency>
Object object = new Object();
int[] arr = new int[10];
System.out.println(ClassLayout.parseInstance(object).toPrintable());
System.out.println(ClassLayout.parseInstance(arr).toPrintable());

锁的升级过程——偏向锁、轻量级锁、重量级锁_第2张图片

锁的状态由低到高

无锁——>偏向锁——>轻量级锁——>重量级锁
注:锁的状态随着竞争情况逐渐升级,但不能降级。

锁状态 锁标志位 Mark Word
偏向锁 101 线程ID I Epoch I 101
轻量级锁 00 指向栈的指针 I 00
重量级锁 10 指向重量级锁的指针 I 00
偏向锁

原因:大多数情况下,锁不仅不存在竞争,且总是由同一线程多次获得。
失效:当一个线程已经获取过偏向锁,另一个线程尝试获取偏向锁时,偏向锁失效。

轻量级锁

原理:在当前线程的栈帧中创建内存复制锁的对象头Mark Word,通过CAS将栈帧中对象头Mark Word替换为执行锁记录的指针,如果替换成功再将修改锁的Mark Word,如果替换失败将升级为重量级锁。

(1)验证无锁

public class Test {
    private static Object lock = new Object();
    public static void main(String[] args) {
       System.out.println(ClassLayout.parseInstance(lock).toPrintable());
    }
}

在这里插入图片描述

注意:顺序是与上面的图片倒着的,有兴趣的可以用Integer.toBinaryString()将二进制后面的int值打印出来对照看一下。

(2)验证偏向锁
-XX:+UseBiasedLocking:开启偏向锁(jdk6及以上默认开启)
-XX:BiasedLockingStartupDelay=0:默认延迟5s启动(这里测试建议开启)

public class Test {
    private static Object lock = new Object();
    public static void main(String[] args) throws InterruptedException {
        System.out.println(ClassLayout.parseInstance(lock).toPrintable());
        synchronized (lock) {
            System.out.println(ClassLayout.parseInstance(lock).toPrintable());
        }
    }
}

锁的升级过程——偏向锁、轻量级锁、重量级锁_第3张图片

关闭偏向锁:-XX:-UseBiasedLocking=false
(3)验证轻量级锁
注意:以下代码可能会出现重量级锁的情况。

public class Test {
    private static final Logger log = LoggerFactory.getLogger(Test.class);
    private static Object o = new Object();
    public static void main(String[] args) throws InterruptedException {
        log.info(ClassLayout.parseInstance(o).toPrintable());
        synchronized (o) {
            log.info(ClassLayout.parseInstance(o).toPrintable());
        }
        new Thread(() -> {
            synchronized (o) {
                log.info(ClassLayout.parseInstance(o).toPrintable());
            }
        }).start();
        Thread.sleep(1000000);
    }
}

锁的升级过程——偏向锁、轻量级锁、重量级锁_第4张图片

(4)验证重量级锁

public class Test {
    private static final Logger log = LoggerFactory.getLogger(Test.class);
    private static Object o = new Object();
    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            synchronized (o) {
                log.info(ClassLayout.parseInstance(o).toPrintable());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {}
            }
        }).start();
        synchronized (o) {
            log.info(ClassLayout.parseInstance(o).toPrintable());
            Thread.sleep(1000);
        }
        Thread.sleep(1000000);
    }
}

锁的升级过程——偏向锁、轻量级锁、重量级锁_第5张图片

你可能感兴趣的:(锁的升级过程——偏向锁、轻量级锁、重量级锁)