并发编程(二十二)Synchronized锁升级-轻量级锁升级为重量级锁

82 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第20天,点击查看活动详情

1.轻量级锁升级为重量级锁流程图

image.png

2.流程图讲解

首先线程1访问同步代码块,此时还是无锁状态,所以给MarkWord中记录的是hashCode等信息。线程1使用CAS修改MarkWord,成功后这个锁成为轻量级锁,线程1分配空间并复制MarkWord到栈帧中的LockRrecord中,并且MarkWord记录的是指向LockRecord中的指针。开始执行同步代码块中的内容。

此时线程2也进来,跟线程1做同样的事情,访问同步代码块,此时还是无锁状态,所以给MarkWord中记录的是hashCode等信息。线程2使用CAS修改MarkWord,结果是失败的,因为MarkWord已经被线程1CAS修改了。此时线程2进行自旋去尝试获取锁,最终还是发现失败,这时,线程2就干了一件事儿,就是弄了一个临时的重量级锁指针。

此时线程1执行完同步代码块后,想CAS替换回LockRecord中记录的信息到MarkWord。发现失败了,因为这个时候,线程2已经把MarkWord中的信息修改为临时的重量级锁指针。此时进入到释放锁并唤醒等待线程。

轻量级锁---重量级锁: 释放锁(前四步)并唤醒等待线程

  1. 线程1 初始化monitor 对象;

  2. 将状态设置为膨胀中(inflating);

  3. 将monitor里边的header属性,set称为对象的markword;(将自己lock record里边的存放的mark word的hashcode,分代年龄,是否为偏向锁 set 到 objectmonitor对象的header属性里)

  4. 设置对象头为重量级锁状态(标记为改为00);然后将前30位指向第1步他初始化的monitor 对象;(真正的锁升级是由线程1操控的)

  5. 唤醒线程2;

线程2 开始争抢重量级锁。(线程2就干了一件事儿,就是弄了一个临时的重量级锁指针吧?还不是最后的重量级锁指针。因为最后的重量级锁指针是线程1初始化的并且是线程1修改的。 而且,线程2被唤醒之后,还不一定能够抢到这个重量级锁。Sync是非公平锁。 线程2费力不讨好,但是线程2做了一件伟大的事情:他是锁升级的奠基者。)