当前位置:网站首页>升级为重量级锁,锁重入会导致锁释放?
升级为重量级锁,锁重入会导致锁释放?
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轻量级锁 重量级锁
边栏推荐
- Does flinkcdc have any solution for mysql's date field type conversion?
- 实战演练 Navicat 中英文模式切换
- 从购买服务器到网站搭建成功保姆级教程~超详细
- R语言使用tidyquant包的tq_transmute函数计算持有某只股票的天、月、周收益率、ggplot2使用条形图可视化股票月收益率数据、使用百分比显示Y轴坐标数据、使用不同的色彩表征正负收益率
- Jupyter shortcuts
- dbeaver连接MySQL数据库及错误Connection refusedconnect处理
- 滚动条样式修改
- 特别数的和
- torch
- 「游戏引擎 浅入浅出」4.1 Unity Shader和OpenGL Shader
猜你喜欢

第02章 MySQL的数据目录【1.MySQL架构篇】【MySQL高级】

matlab simulink 粒子群优化模糊pid控制的电机泵

WebSocket implements chat function

Vim简介

Hunan institute of technology in 2022 ACM training sixth week antithesis

Qt Widget 项目对qml的加载实例

字符中的第一个唯一字符

I have three degrees, and I have five faces. I was "confessed" by the interviewer, and I got an offer of 33*15.

仿牛客网讨论社区项目—项目总结及项目常见面试题

从零开始—仿牛客网讨论社区项目(一)
随机推荐
Talk about the bugs in using for in to traverse the array in js
AspNet.WebApi.Owin custom Token request parameters
MVVM project development (commodity management system 1)
curl (7) Failed connect to localhost8080; Connection refused
小白的0基础教程SQL: 安装MYSQL 03
深度比较两个对象是否相同
Solve the problem of page flicker caused by browser scroll bars
Vim简介
响应式织梦模板园林花卉类网站
2022.7.26 Mock Competition
uva12326
mysql的行锁和间隙锁
More than 2022 cattle guest school game 4 yue
ORACLE modify another user package (package)
Dart exception details
字符中的第一个唯一字符
05-SDRAM: Arbitration
选择排序—直接选择排序和堆排序
Flip letters using string container
数据机构----线性表之单向链表