当前位置:网站首页>升级为重量级锁,锁重入会导致锁释放?
升级为重量级锁,锁重入会导致锁释放?
2022-08-01 06:48:00 【皮皮杨233】
目录
前言
近日,看到有些文章说:“产生竞争时,轻量级锁升级为重量级锁,此时持锁线程执行 CAS 操作(锁重入) 会失败,所以将会提前释放锁”
首先,持锁线程可能连同步块都未执行完成就平白无故将锁释放掉,怎么想都不合理
接下来的实验将证明上述 “提前释放锁” 结论的错误性
实验
如何验证
锁升为重量级锁后,如果会释放锁,那么锁重入肯定会失败;所以只需验证升级之后,锁重入不会阻塞即可
流程说明
main
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
try {
// Thread0 在方法中首次获取锁
first();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
Thread.sleep(5000);
new Thread(() -> {
log.debug("---------------------------Thread1 首次尝试加锁---------------------------");
synchronized (lock){
log.debug(ClassLayout.parseInstance(lock).toPrintable());
}
}).start();
}
- 创建 Thread0,执行包含获取锁操作的方法
- 主线程睡眠 5s,确保 Thread0 先执行,先获取锁,并且此时为轻量级锁
- 创建 Thread1,尝试获取锁,产生锁竞争,导致锁升级
first
static void first() throws InterruptedException {
log.debug("---------------------------Thread0 首次尝试获取锁---------------------------");
synchronized(lock){
log.debug("Thread0 首次获取锁成功!");
log.debug(ClassLayout.parseInstance(lock).toPrintable());
Thread.sleep(10000);
// 第二次获取锁(锁重入)
reentrant();
}
}
- Thread0 首次获取锁,打印锁对象的对象头
- 先睡眠 10s(Thead1 在此期间被创建并尝试获取锁,导致发生锁升级)
- 然后调用 reentrant() 方法,进入该方法会再次执行一次获取锁的操作
reentrant
static void reentrant(){
log.debug("---------------------------Thread0 尝试锁重入---------------------------");
synchronized(lock){
log.debug("Thread0 锁重入成功!");
log.debug(ClassLayout.parseInstance(lock).toPrintable());
}
}
- Thread0 尝试再次获取锁(锁重入)
- 若未阻塞,则会执行打印,验证了结论的错误性
- 若阻塞,代表锁已释放并被其他线程获取,说明结论是正确的
结果
- 红色框:表示 Thread0 的时间线
- 蓝色框:表示 Thread1 的时间线
- 紫色框:表示锁的状态
时间线:
第 26s 主线程创建 Thread0 并启动,然后进入 5s 睡眠;Thread0 尝试第一次获取锁,成功了,锁状态 00 代表轻量级锁,然后进入 10s 睡眠
5s 之后的第 31s,主线程创建 Thread1 并启动;Thread1 尝试第一次获取锁,由于 Thread0 还在睡眠中,并且未释放锁,此时发生锁竞争,锁升级为重量级锁;Thread1 获取锁失败,进入阻塞
10s 之后的第 36s,Thread0 执行锁重入,成功了,锁状态 10 代表已升级为重量级锁;Thread0 释放锁,Thread1 从阻塞中被唤醒,并且获取锁成功
总结
实验结果表明,即使锁已经升级为重量级锁,持锁线程执行锁重入操作并未发生阻塞,所以也就不存在释放锁一说
锁已经升级,但是持锁线程可能确实并不知情,本人猜测:在锁重入或者解锁时发现已经升级为重量级锁,并且接下来不是对锁对象的对象头执行 CAS 操作,而是对它指向的 monitor 对象中的 owner 属性执行 CAS 操作
(补充:轻量级锁,锁重入执行 CAS 操作都会失败,但是它只会生成锁记录,而不是直接释放锁)
并发编程 synchronized (五) 重量级锁、轻量级锁_皮皮杨233的博客-CSDN博客_synchronized轻量级锁 重量级锁
边栏推荐
猜你喜欢
sum of special numbers
Dialogue with the father of MySQL: One excellent programmer is worth 5 ordinary programmers
数据机构----线性表之单向链表
爬虫基本原理介绍、实现以及问题解决
Windows taskbar icon abnormal solution
Srping中bean的生命周期
2022.7.26 Mock Competition
Dbeaver connect the MySQL database and error Connection refusedconnect processing
JS的运行原理
Flip letters using string container
随机推荐
Windows taskbar icon abnormal solution
Induction jian hai JustFE 2022/07/29 team, I learned the efficient development summary (years)
阿里三面:MQ 消息丢失、重复、积压问题,该如何解决?
Dbeaver connect the MySQL database and error Connection refusedconnect processing
torch
Xiaobai's 0 Basic Tutorial SQL: An Overview of Relational Databases 02
权重等比分配
AspNet.WebApi.Owin 自定义Token请求参数
leetcode125 Verify palindrome string
旋度(7)连接失败localhost8080;连接拒绝了
Robot growth in China
R语言使用tidyquant包的tq_transmute函数计算持有某只股票的天、月、周收益率、ggplot2使用条形图可视化股票月收益率数据、使用百分比显示Y轴坐标数据、使用不同的色彩表征正负收益率
深度比较两个对象是否相同
Classwork (7) - #598. remainder operation (mod)
CSP-S2019兴奋不已
ORACLE 实现另外一个用户修改包(package)
weight distribution
使用string 容器翻转 字母
Three aspects of Ali: How to solve the problem of MQ message loss, duplication and backlog?
从零开始—仿牛客网讨论社区项目(一)