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

对象的内存布局
  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)

在这里插入图片描述

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

在这里插入图片描述

锁的状态由低到高

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

锁状态锁标志位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());
        }
    }
}

在这里插入图片描述

关闭偏向锁:-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)验证重量级锁

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);
    }
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值