【一文读懂】 Java并发 - 锁升级原理

news2025/1/12 7:49:55

要明白锁的原理,首先要知道对象头

Java对象头

在Java中,一个对象一般由两部分组成 :1、对象头 ; 2、对象的成员变量信息

在32位的虚拟机中:

(1)普通对象的对象头长度64bit(8字节):
其中的32bit是Mark Word,另外32位是Klass Word,如下:

Mark Word (32 bits)Klass Word (32 bits)

(2)数组对象的对象头长度96bit(12自己):
除了Mark Word和Klass Word,还有32bit的 array length,如下:

Mark Word(32bits)Klass Word(32bits)array length(32bits)

什么是 Mark Word 什么是 Klass Word 什么是array length ?

  • array length - 很明显这是标明数组长度的字段
  • Klass Word - 对象类型指针,通过该字段标明当前对象所属的类
  • Mark Word - 下面着重介绍

在不同状态下,Mark Word 会有不同的表现形式,对应关系如下:

在这里插入图片描述
Normal 就是对象的正常状态,以该状态为例

  • 25位是对象的hashcode
  • 4位是age,在垃圾回收中的分代年龄
  • 1位biased_lock,标明是否是对象锁
  • 2位(01),表明当前的加锁状态

Biased 是偏向锁状态
Lightweight Locked 是轻量级锁状态
Heavyweight Locked 是重量级锁状态
Marked for GC 是在JVM进行GC时的状态

无论是偏向锁、轻量级锁、重量级锁,都是在对象头中的Mark Word做文章

锁升级

在默认情况下,synchronized 会首先使用偏向锁,当发现存在竞争时,就会升级为轻量级锁,当竞争比较激烈时,轻量级锁就会升级为重量级锁
但是我们可以通过添加 VM 参数 -XX:-UseBiasedLocking 手动关闭偏向锁,那么synchronized 会直接进入轻量级锁

为什么会有锁升级?

因为从偏向锁 - 轻量级锁 - 重量级锁,互斥程度会越来越高,但是性能代价也越来越大,所以在一开始,如果资源竞争不是很激烈,应该优先选择程度较轻的锁,以下是《Java并发编程的艺术》一书中的原话

Java SE 1.6为了减少获得锁和释放锁带来的性能消耗,引入了“偏向锁”和“轻量级锁”,在
Java SE 1.6中,锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状
态和重量级锁状态,这几个状态会随着竞争情况逐渐升级。锁可以升级但不能降级,意味着偏
向锁升级成轻量级锁后不能降级成偏向锁。这种锁升级却不能降级的策略,目的是为了提高
获得锁和释放锁的效率,下文会详细分析。

重量级锁原理

操作系统会提供 Monitor 对象,对某个对象加上重量级锁之后,该对象头中的 Mark Word 中就被设置成指向 Monitor 对象的指针 即上图所示的 ptr_to_heavyweight_monitor:30

在Monitor对象中会有两个属性: 1、Owner ;2、EntryList
Owner - 指当前这个对象的锁是由哪个对象持有的
EntryList - 是一个线程队列,当其他线程来竞争该对象锁失败时,就会进入EntryList 中阻塞

因为重量级锁的加锁过程需要使用到操作系统提供的 Monitor 对象,换言之,属于内核级别,因此性能代价是较大的,如果一个对象虽然有多线程要加锁,但加锁的时间是错开的(也就是没有竞争),那么可以使用轻量级锁来优化

重量级锁的自选优化

重量级锁竞争的时候,可以使用自旋来进行优化,如果当前线程自旋成功(即这时候持锁线程已经退出了同步块,释放了锁),当前线程就可以避免阻塞

轻量级锁

每个线程的每个栈帧都会包含一个锁记录的结构

锁记录包含两个部分,其中一个部分用存储上锁对象的 Mark Word,另外一部分是对象指针 Object reference,用于指向上锁对象的地址

上锁过程如下,让锁记录中 Object reference 指向上锁对象,并尝试用 cas 替换 Object 的 Mark Word,将 Mark Word 的值存入锁记录

在这里插入图片描述

如果 cas 替换成功,对象头中存储了 锁记录地址和状态 00 ,表示由该线程给对象加锁,结果如下

在这里插入图片描述

如果cas 失败,有两种情况:

  • 其它线程已经持有了该 Object 的轻量级锁,这时表明有竞争,进入锁膨胀过程
  • 自己执行了 synchronized 锁重入,那么再添加一条 Lock Record 作为重入的计数,如下:

在这里插入图片描述

解锁时有如下两种情况

  • 锁记录的值为 null,表示有重入,这时重置锁记录,表示重入计数减一
  • 锁记录的值不为 null,这时使用 cas 将 Mark Word 的值恢复给对象头,如果失败,说明轻量级锁进行了锁膨胀或已经升级为重量级锁,进入重量级锁解锁流程

锁膨胀过程

假设此时Thread-0已经对某个对象上了轻量级锁,现实Thread-1也尝试对改对象加锁,必然加锁失败,进入锁升级

  1. 即为 Object 对象申请 Monitor 锁,让 Object 指向重量级锁地址
  2. 然后自己进入 Monitor 的 EntryList 阻塞

如下图

在这里插入图片描述

当 Thread-0 退出同步块解锁时,使用 cas 将 Mark Word 的值恢复给对象头,失败。这时会进入重量级解锁流程,即按照 Monitor 地址找到 Monitor 对象,设置 Owner 为 null,唤醒 Entry List 中 的Thread-1 线程

轻量级锁缺点

在很多情况下,一个对象在某段时间内,会不停被同一个线程上锁,即不断发生锁重入,这就会频繁的进行Mark Word的cas操作,这也是存在一定性能损耗的,因此诞生了偏向锁来优化

偏向锁

只有第一次使用 CAS 将线程 ID 设置到对象的 Mark Word 头,之后发现这个线程 ID 是自己的就表示没有竞争,不用重新 CAS。以后只要不发生竞争,这个对象就归该线程所有

比较Normal状态和偏向锁状态的Mark Word:

在这里插入图片描述

我们发现Normal状态下 biased_lock 是0,偏向锁的 biased_lock 是1; biased_lock 是偏向锁的开启标志,0表示禁用,1表示开启

而且对于Normal,用了 31bit 去存储对象的hashcode;
而偏向锁状态下不在记录对象的hashcode,而是记录线程编号:初始状态下 54bit 的thread标记都是0,当有线程对该对象上轻量级锁后, 54bit 的thread标记记录下当前线程编号,而且那么线程出了临界区释放了锁,thread不会发生改变,所以当该线程对该对象进行锁重入或者重新上锁时,发现里面的线程编号就是自己,就表示没有竞争,不用 CAS

而如果有另外一个线程要对该对象上锁时,发现当前记录着其他线程的编号,就进行锁膨胀,升级为轻量级锁

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/927552.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Javascript 编写一个简单的聊天机器人

在本 Web 开发教程中,我们将了解如何使用 HTML、CSS 和 vanilla JavaScript 创建基本的聊天机器人。本练习侧重于 JS 基础知识,而不是任何类型的人工智能 (AI)。为了使该过程更简单,更易于学习,我没有使用任…

ffmpeg windows环境MinGW+msys2编译so库

一、安装MinGW 1.1、下载MinGW 1.2、下载完成后,会得到一个名为 mingw-get-setup.exe 的安装包,双击打开它,可以看到如下的对话框: 1.3、直接点击“Install”,进入下面的对话框 1.4、可根据自己操作系统的实际情况&am…

数据库MySQL中left join多个条件下的执行

1 基础表 创建表A 表B create table testA(id int, name varchar(10)); create table testB(id int, name varchar(10)); 2 插入数据 insert into testA values(1,zhangssa),(2,lisi),(3,wangwu) insert into testB values(2,zhangssa2),(3,lisi2),(4,wangwu4) 3 left joi…

WPF自定义命令及属性改变处理

1、项目建构 2、自定义命令 namespace WpfDemo.Base {public class MyCommand : ICommand{Action executeAction;public MyCommand(Action action){executeAction action;}public event EventHandler? CanExecuteChanged;public bool CanExecute(object? parameter){retu…

ssm会员管理系统源码和论文

ssm会员管理系统源码和论文062 开发工具:idea 数据库mysql5.7 数据库链接工具:navcat,小海豚等 技术:ssm 摘 要 随着科学技术的飞速发展,各行各业都在努力与现代先进技术接轨,通过科技手段提高自身的优势&#x…

36k字从Attention讲解Transformer及其在Vision中的应用(pytorch版)

文章目录 0.卷积操作1.注意力1.1 注意力概述(Attention)1.1.1 Encoder-Decoder1.1.2 查询、键和值1.1.3 注意力汇聚: Nadaraya-Watson 核回归1.2 注意力评分函数1.2.1 加性注意力1.2.2 缩放点积注意力1.3 自注意力(Self-Attention)1.3.1 自注意力的定义和计算1.3.2 自注意…

邀请函 | 区块链如何助力建设“健康中国”?ESG系列研讨会“医疗”专场来袭!

党的十九大报告指出,要全面实施健康中国战略,为人民群众提供全方位全周期健康服务。今年7月,国家卫生健康委等六部门联合印发了《深化医药卫生体制改革2023年下半年重点工作任务》,明确指出要开展全国医疗卫生机构信息互通共享三年…

基于 vue2 发布 npm包

背景:组件化开发需要,走了一遍发布npm包的过程,采用很简单的模式实现包的发布流程,记录如下。 项目参考:基于vue的时间播放器组件,并发布到npm_timeplay.js_xmy_wh的博客-CSDN博客 1、项目初始化 首先&a…

AKM10-58C大电流TVS二极管参数:58V 10000A

东沃(DOWO)AKM10-76C是什么二极管? 东沃生产AKM10-76C大电流TVS二极管吗?有现货吗? 除了AKM10-76C外,东沃(DOWO)生产的贴片大电流二极管还有哪些型号? …… AKM10-76C是厂…

VMware 新装 CentOS 7 连不上网络的【解决方法】

文章目录 1)虚拟机设置2)虚拟网络编辑器3)Linux 网卡设置4)检查网络状态参考资料: 安装好虚拟机之后,将来会在虚拟机内的系统中安装各种应用,如果虚拟机内的系统连不上网,则无从谈起…

PythonJS逆向解密——实现翻译软件+语音播报

前言 嗨喽,大家好呀~这里是爱看美女的茜茜呐 环境使用: python 3.8 pycharm 模块使用: requests --> pip install requests execjs --> pip install PyExecJS ttkbootstrap --> pip install ttkbootstrap pyttsx3 --> pip install pyttsx3 第三…

interview2-框架篇

一、Spring篇 1、Spring (1)Bean线程安全问题 不是线程安全的。Spring框架中有一个Scope注解,默认的值就是singleton,单例的。因为一般在spring的bean的中都是注入无状态的对象,没有线程安全问题,如果在b…

【Focal Loss】解决类别不平衡问题,增加对困难样本的挖掘

Focal Loss是在交叉熵损失函数的基础上增加了一个平衡因子 α \alpha α和一个聚焦因子 γ \gamma γ,分别用来调节不同类别样本的权重以及难分样本和易分样本之间的权重一个样本的交叉熵损失函数如下: p t p_t pt​表示将该样本分类为t的概率一个样本的…

8个好用的产品设计工具,收藏一下

产品设计在设计工作中是非常重要的一个环节,它是对产品的初步构思,能明确规定产品设计的细节。今天本文将为大家推荐8个好用的产品设计工具,不仅操作方便,而且简单好用,能充分提高工作效率,一起来看看吧&am…

政府网站定期巡检:构建高效、安全与透明的数字政务

在数字时代,政府网站已不仅仅是一个信息发布窗口,更是政府与公众互动的桥梁、政务服务的主要渠道以及数字化治理的重要平台。因此,确保政府网站的高效运行、信息安全与透明公开就显得尤为重要。在此背景下,定期的网站巡检与巡查成…

搭建微信小程序商城的详细教程

微信小程序商城是一种通过微信平台进行线上购物的应用,它具有界面友好、交互便利、功能实用等特点,成为越来越多企业和个人创业者的选择。下面,我们将为大家介绍如何搭建微信小程序商城的详细教程。 第一步,登录乔拓云平台进入后台…

D.OASIS City 和 Warrix 在The Sandbox 庆祝 Rise of the 10th Legend十周年

D.OASIS 首次展示了变革性娱乐 D.OASIS City,正如它与 WARRIX 一起承诺的那样。WARRIX 是获得泰国国家队球衣生产授权的标志性运动服装品牌。 这款激动人心的游戏冒险游戏于今天推出,让用户能够投入 D.OASIS City x WARRIX:Rise of the 10th…

数据库怎么备份文件,数据库一般怎么备份

在当今的数字世界中,数据已经成为企业的生命线。无论是客户数据、业务数据还是内部流程,都需要通过数据库进行存储和管理。然而,数据的安全性和完整性也成为企业面临的一大挑战。在这种情况下,数据库备份尤为重要。那么&#xff0…

陪诊系统源码开发:实现个性化医疗陪护的创新之路

陪诊系统的源码开发在现代医疗中具有重要意义。本文将通过代码示例介绍陪诊系统的源码开发,展示如何实现个性化医疗陪护的创新方案。 1. 安装和环境设置: 首先,确保你的开发环境中已经安装了合适的编程语言和框架,比如Python和…

python 模块xlrd 读取.xls文件

Python操作Excel的模块有很多,并且各有优劣,不同模块支持的操作和文件类型也有不同。下面是各个模块的支持情况: xlwt:xlwt 写入.xls文件xlwings:xlwings 读取写入Excel文件openpyxl:openpyxl 读取写入.xl…