synchronized锁膨胀、锁升级、锁优化的过程

news2024/11/24 22:48:28

参考文章
Java中的偏向锁,轻量级锁, 重量级锁解析_萧萧九宸的博客-CSDN博客

本文是本人对以上文章的整理,建议先去看以上文章。

在Java中,一个锁对象的四种状态:

  • 无锁
  • 偏向锁
  • 轻量级锁
  • 重量级锁
    在Java中,一个锁就是一个对象

synchronized代码块是由一对monitorentermonitorexit字节码指令实现,这两个指令中间放的就是synchronized中同步代码块中的字节码指令。

在JDK1.6之前,synchronized锁是重量级锁,性能开销严重,从JDK1.6开始,为了改善同步性能,又引入了偏向锁和轻量级锁
锁的重量级的排序是:
无锁 < 偏向锁 < 轻量级锁 < 重量级锁
锁的升级是单向的,只能从低到高,不会出现锁的降级。
随着线程竞争的激烈程度增加,伴随有锁升级的现象,锁的重量程度越来越大。

JVM默认是关闭可偏向锁机制的,如果想要开启可偏向机制,在启动时,通过JVM参数指定

-XX:-UseBiasedLocking

大致的锁膨胀的过程是这样的:

无锁 --> 偏向锁

偏向锁本质上也是一个无锁化编程解决方案。

大部分的情况下,锁不存在多线程竞争,而是总是由同一个线程多次获得,为了减少同一线程获取锁的成本而引入了偏向锁
偏向锁的核心理念就是:如果一个线程获取了锁,那个锁对象就进入偏向模式,“偏向于这个线程”,当这个线程再次请求这个锁时,无需再做同步操作,可以直接获取到该锁,可以省去很多申请锁、加锁的操作,从而减少同步的成本

当初始化锁对象时,会首先判断系统是否开启了“可偏向”机制,如果未开启,则会创建一个普通的无锁状态的对象,并初始化对象头中的内容是hashCode和分代年龄。
若开启了可偏向机制,则会初始化锁对象是可偏向的未偏向状态,即可偏向的无锁状态,此时对象头中MarkWord的内容是 空的线程ID + epoch + 对象分代年龄 + 可偏向标志位

由无锁 到 偏向锁的过程,本质上就是将线程id写入到锁对象的对象头中的MarkWord的过程。
具体的过程是:

  1. 首先读取目标对象的MarkWord,判断此时锁对象是否处于可偏向状态。
  2. 如果是可偏向状态,则尝试用CAS操作,将自己的线程ID写入到锁对象的MarkWord中。
    1. 如果CAS操作成功,则认为此线程已经获取到了对象的偏向锁,执行同步代码块。
    2. 一个线程执行完之后,并不会将锁对象中的MarkWord中的线程ID赋回空值。这样做的好处是:如果线程需要再次对这个锁对象加锁,而之前此锁对象一直没有被其他线程获取过锁,依旧停留在可偏向的状态下,即可以在不修改对象头的情况下,直接获取该对象的偏向锁,直接认为偏向成功
    3. 如果CAS操作失败,则说明有另一个线程B抢先获取了偏向锁。这种状态说明此锁的竞争比较激烈,此时需要撤销线程B的偏向锁,将线程B持有的锁升级为轻量级锁。
  3. 如果是已偏向状态,则检测对象头中的MarkWord中的线程ID是否是当前线程ID
    1. 如果是,则表明本线程已经获取到了偏向锁,可以直接继续执行同步代码块
    2. 如果不相等,则证明该对象偏向于其他线程,需要撤销偏向锁。

注意:偏向锁的撤销过程,并不是将锁对象恢复到无锁可偏向的状态,而是直接将该锁对象的状态修改至“轻量级锁定”状态。

偏向锁 --> 轻量级锁

当存在多个线程竞争某一个对象时,会撤销偏向锁,升级到轻量级锁。
当偏向锁加锁失败后,会升级到轻量级锁。

偏向锁在撤销后,锁对象可能处于两种状态:

  • 一种是不可偏向的无锁状态 (之所以不可偏向,因为系统已经检测到多于一个线程竞争锁对象,升级到了轻量级锁定状态)

  • 另一种是不可偏向的已锁状态 (轻量级锁定)

为什么会出现上述两种状态,因为偏向锁不存在解锁操作,只有撤销操作,触发撤销操作时:

  • 原来已经获取了偏向锁的线程可能已经执行完了同步代码块,使得对象处于“闲置状态”,相当于原有的偏向锁已经过期无效了。此时该对象就应该被直接转换为不可偏向的无锁状态
  • 原来已经获取了偏向锁的线程可能还没有执行完成同步代码块,偏向锁依旧有效,此时锁对象就应该被转换为轻量级锁定的状态

轻量级加锁的过程

  1. 在进入同步代码块的时候,如果锁对象的状态是无锁状态,锁标志位是01。
  2. 会在当前线程的栈帧中创建一个锁记录Lock Record的空间,用来存储锁对象目前的MarkWord的拷贝。(不论是Java方法栈,还是本地方法栈,都是线程私有的
  3. 拷贝对象头中的MarkWord到锁记录中。
  4. 拷贝完成后,JVM会利用CAS操作尝试将锁对象的MarkWord更新为指向锁记录LockRecord的指针,并将Lock Record里的owner指向对象的MarkWord。
  5. 如果更新成功,那么这个线程就拥有了该对象的锁,并且对象的MarkWord的锁标志位置为“00”,表示此对象处于轻量级锁定的状态。

简单点说上面的过程:

  1. 首先检查MarkWord中标志位,锁对象是否处于不可偏向的无锁状态

  2. 然后在当前线程的栈帧中,创建用于存储锁记录LockRecord的空间,并将对象头中的MarkWord拷贝LockRecord中。

  3. 然后尝试用CAS将对象头中的MarkWord替换为指向锁记录的指针。

    • 如果成功,当前线程加锁成功
    • 如果失败,表示该对象已经加锁,先进行自旋操作,再次尝试CAS争抢,如果仍未竞争到,进一步升级到重量级锁。

轻量级锁能够提升程序性能的依据是“绝大部分的情况下,在整个同步期间,是不会存在多线程竞争的”,因此轻量级锁的适应场景是线程交替执行同步代码块的场合,如果同一时间访问同一锁的场合,就会膨胀到重量级锁

重量级锁

重量级锁本质就是操作系统内的管程机制,管程机制就是对信号量操作进行了封装。
关于synchronized重量级锁的原理,可以看我的这篇文章关于Java中synchronized的实现原理_秋天code的博客-CSDN博客

锁优化

自旋锁

轻量级锁加锁失败后,虚拟机为了避免线程真实地在操作系统层面挂起,会进行自旋锁的优化手段。
如果要在操作系统层面挂起一个线程,会涉及到用户态切换到和心态,这个过程是需要损耗系统性能的。
自旋锁的假设是,当前线程会在不久后可以获取到锁,因此虚拟机会让该线程进行自旋,经过若干轮等待后,如果得到了锁,就进入临界区。如果还得不到锁,那么在操作系统层面就会真的挂起这个线程。

锁消除

锁消除是虚拟机另外一种锁优化的手段,在JIT编译期间,JVM通过对上下文的扫描,发现有一段临界区是不可能存在竞争的,对于这段临界区来说,没有加锁的必要了,因此会消除这个锁。
例如,一个变量是方法内部的,不可能被其他线程访问到,此时就会消除这个方法的同步。

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

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

相关文章

推断统计方法(假设检验)

统计方法除了描述统计方法之外还有推断统计&#xff0c;推断统计包括参数估计和假设检验&#xff0c;假设检验的概念就是先假设后检验&#xff0c;运用的是数学上的反证法&#xff1b;假设检验是利用样本数据提供的信息&#xff0c;对未知总体分布的某些方面&#xff08;如总体…

STM32F103C8T6蓝牙OTA教程

一、准备与简介 1. 准备材料 文章使用的软硬件并不局限&#xff0c;下述仅作参考&#xff0c;文章的所有使用的工程可在文末获取&#xff08;百度网盘Github&#xff09; 1&#xff09;STM32F103C8T6核心板 2&#xff09;下载器&#xff08;PWLINK&#xff09; 3&#xff0…

Vscode 常用操作教程

一、语言换成中文 这是我们可以直接点击左边栏第四个图标搜索插件 chinese ,也可以直接ctrlshiftp快捷键也会出来如图所示图标&#xff0c;出来chinese 插件之后选择安装install,安装完成之后重新ctrlshiftp会出现如图所示页面 找到我的鼠标在的地方对应的中文&#xff0c;此时…

【工作中问题解决实践 十二】使用@JsonTypeInfo实现请求数据对象多态

最近在处理接口请求进行数据写入的一个case时&#xff0c;我希望上游只使用我一个写入接口去实现不同类型的数据写入&#xff0c;而上游的数据写入Model是各不相同的&#xff0c;这就要求我接口的一个对象可以应对上游不同类型对象的写入请求。关于Jackson的概念不再赘述&#…

SQL进阶--SQL的常用技巧

一、ORDER BY FIELD() 自定义排序逻辑 排序 ORDER BY 除了可以用 ASC 和 DESC&#xff0c;还可以通过**ORDER BY FIELD(str,str1,...)**自定义字符串/数字来实现排序。这里用 order_diy 表举例&#xff0c;结构以及表数据展示&#xff1a; 二、CASE 表达式 「case when then el…

UI设计师个人工作感悟5篇

UI设计师个人工作感悟一 工作一年了&#xff0c;结合我自身谈谈UI设计的重要性。现在主流的论坛建站程序有两种 Phpwind 和Discuz(Phpwind被阿里巴巴收购 Discuz被腾讯收购这两个论坛程序都是开源免费的)&#xff0c;利用这两种程序我都分别建立过论坛&#xff0c;我第一次用的…

7-15 然后是几点

有时候人们用四位数字表示一个时间&#xff0c;比如 1106 表示 11 点零 6 分。现在&#xff0c;你的程序要根据起始时间和流逝的时间计算出终止时间。 读入两个数字&#xff0c;第一个数字以这样的四位数字表示当前时间&#xff0c;第二个数字表示分钟数&#xff0c;计算当前时…

高效解决在pycharm环境下的UserWarning: loaded more than 1 DLL from .libs这类问题

文章目录 问题解决方案Plan APlan B 解决&#xff01; 问题 这说明因同时存在多个动态链接库而存在冲突&#xff0c;所以需要删除其中一个 解决方案 Plan A Plan B 如果Plan A没用&#xff0c;就重装numpy&#xff0c;因为这个库就是numpy的 pip uninstall numpy pip insta…

zabbix-6.4 监控 MySQL

目录 1、rpm安装zabbix_agentd服务 2、编写zabbix_agentd.conf文件 3、编写模板文件 4、创建mysql用户并赋权限 5、创建.my.cnf文件 6、将规则添加到SELinux策略中 注意&#xff1a; 若模板无法读取.my.cnf 信息&#xff0c;从而导致监控报错&#xff0c;可以尝试修改模…

使用Python将文本转换为语音的简易应用

正文&#xff1a; 在本篇博客中&#xff0c;我们将介绍如何使用Python编写一个简单的应用程序&#xff0c;将文本转换为语音。我们将使用pyttsx3库进行文本到语音的转换&#xff0c;并通过pygame库来播放生成的语音。 C:\pythoncode\new\text2speech.py 首先&#xff0c;我们…

ReentrantReadWriteLock

关于读写锁状态的存取 // ReentrantReadWriteLock.Sync static final int SHARED_SHIFT 16; static final int SHARED_UNIT (1 << SHARED_SHIFT); static final int MAX_COUNT (1 << SHARED_SHIFT) - 1; static final int EXCLUSIVE_MASK (1 <&l…

小白到运维工程师自学之路 第七十三集 (kubernetes应用部署)

一、安装部署 1、以Deployment YAML方式创建Nginx服务 这个yaml文件在网上可以下载 cat nginx-deployment.yaml apiVersion: apps/v1 #apiVersion是当前配置格式的版本 kind: Deployment #kind是要创建的资源类型&#xff0c;这里是Deploymnet metadata: #metadata是该资源…

快手商品详情数据API 抓取快手商品价格、销量、库存、sku信息

快手商品详情数据API是用来获取快手商品详情页数据的接口&#xff0c;请求参数为商品ID&#xff0c;这是每个商品唯一性的标识。返回参数有商品标题、商品标题、商品简介、价格、掌柜昵称、库存、宝贝链接、宝贝图片、商品SKU等。 接口名称&#xff1a;item_get 公共参数 名…

JS实现树形结构、一维数组以及map之间的转换

const treeData[ {id:1, name:中国, children:[ {id:11,name:河南省,children:[{id:111,name:南阳市,children:[{id:1111,name:淅川县,children:null}]},{id:112,name:郑州市,children:[{id:1121,name:中牟县,children:null}]}] }, {id:22,name:广东省,children:[{id:221,name:…

【【verilog典型电路设计之流水线结构】】

verilog典型电路设计之流水线结构 下图是一个4位的乘法器结构&#xff0c;用verilog HDL 设计一个两级流水线加法器树4位乘法器 对于流水线结构 其实需要做的是在每级之间增加一个暂存的数据用来存储 我们得到的东西 我们一般来说会通过在每一级之间插入D触发器来保证数据的联…

创建Azure资源锁

锁的介绍 在Azure中&#xff0c;资源锁是一种用于保护订阅、资源组或者单个资源的机制。它可以防止对受锁定的资源进行删除或修改操作&#xff0c;帮助确保资源的连续可用性和安全性。 Azure中的资源锁可以分为两种类型&#xff1a; 删除锁&#xff08;CanNotDelete&#xf…

实现Excel数据复制分录信息粘贴到金蝶单据体中

>>>适合KIS云专业版V16.0|KIS云旗舰版V7.0|K/3 WISE 14.0等版本<<< 实现Excel数据复制分录信息粘贴到金蝶单据体分录中,在采购订单|采购入库单|销售订单|销售出库单等类型单据中,以少量的必要字段在excel表格中按模板填列好,很方便快捷地复制到金蝶单据表体…

三分钟完美解决你的C盘内存过大爆红

一、清理回收站 二、清理桌面 建议一 不要在桌面放太多图标或者文件会占用过多的内存,可以放到其他盘建议二、 将位置移动到别的盘 三、手动删除下载文件与缓存文件 日常使用中会通过Windows下载各种文件资料到电脑中&#xff0c;它默认也是直接下载在C盘中的。如果我们在以…

ssm+JSP的乡镇自来水收费系统源码和论文PPT

ssmJSP的乡镇自来水收费系统源码和论文PPT014 开发工具&#xff1a;idea 数据库mysql5.7(mysql5.7最佳) 数据库链接工具&#xff1a;navcat,小海豚等 开发技术&#xff1a;java ssm tomcat8.5 一、课题背景与意义 随着我国经济建设迅速发展&#xff0c;乡镇规模日益扩大&am…

RK3568 HDMI接口

一.简介 HDMI接口&#xff0c;中文全称为高清多媒体接口。是一种全数字化视频以及声音发送接口&#xff0c;能够发送没有压缩的音频以及视频信号。HDMI接口可以使用在机顶盒、DVD播放机等设备商。除此之外&#xff0c;HDMI接口还可以同时发送音频以及视频信号&#xff0c;简化…