JVM原理(二四):JVM虚拟机锁优化

高效并发是从JDK 5升级到JDK 6后一项重要的改进项,HotSpot虛 拟机开发团队在这个版本上花费了大量的资源去实现各种锁优化技术,如适应性自旋( Adaptive Spinning)、锁消除( Lock Elimination)、锁膨胀(Lock Coarsening)、轻量级锁(Lightweight Locking)、偏向锁( Biased Locking)等,这些技术都是为了在线程之间更高效地共享数据及解决竞争问题,从而提高程序的执行效率。

1. 自旋锁与自适应自旋

原因:共享数据的锁定状态只会持续很短的一段时间,为了这段时间去挂起和恢复线程并不值得。

解决方案:我们可以让后面请求锁的那个线程“稍等一会”,但不放弃处理器的执行时间,看看持有锁的线程是否很快就会释放锁。为了让线程等待,我们只须让线程执行一个忙循环(自旋),这项技术就是所谓的自旋锁。


优势:如果所被占用的时间很短,那么自旋锁效果就非常好。

缺点:如果被占用的时间长,那么自旋锁只会白白浪费资源。


自适应自旋锁:自适应意味着自旋的时间不再是固定的了,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定的。

前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定的。如果在同一个锁对象上,自旋等待刚刚成功获得过锁,并且持有锁的线程正在运行中,那么虚拟机就会认为这次自旋也很有可能再次成功,进而允许自旋等待持续相对更长的时间,比如持续100次忙循环。另一方面,如果对于某个锁,自旋很少成功获得过锁,那在以后要获取这个锁时将有可能直接省略掉自旋过程,以避免浪费处理器资源。有了自适应自旋,随着程序运行时间的增长及性能监控信息的不断完善,虚拟机对程序锁的状况预测就会越来越精准,虚拟机就会变得越来越“聪明”了。

2. 锁消除

锁消除是指虚拟机即时编译器在运行时,对一些代码要求同步,但是对被检测到不可能存在共享数据竞争的锁进行消除。

判定依据:来源于逃逸分析的数据支持,如果判断到一段代码中,在堆上的所有数据都不会逃逸出去被其他线程访问到,那就可以把它们当作栈上数据对待,认为它们是线程私有的,同步加锁自然就无须再进行。

3. 锁粗化

原则上,我们推荐使用同步代码块中的作用范围尽可能小,但是一系列连续操作都对同一个对象进行加锁和解锁那就是对性能的浪费了。

4. 轻量级锁

轻量级锁:设计的初衷是在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗


对象头存储锁标志:

我们简单回顾了对象的内存布局后,接下来就可以介绍轻量级锁的工作过程了:在代码即将进入同步块的时候,如果此同步对象没有被锁定(锁标志位为“01”状态),虚拟机首先将在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储锁对象目前的M ark Word的拷贝(官方为这份拷贝加了一个Displaced前缀,即DisplacedMarkWord),这时候线程堆栈与对象头的状态如图13- 3所示。

然后,虚拟机将使用CAS操作尝试把对象的Mark Word更新为指向Lock Record的指针。如果这个更新动作成功了,即代表该线程拥有了这个对象的锁,并且对象Mark Word的锁标志位(Mark Word的最后两个比特)将转变为“00”,表示此对象处于轻量级锁定状态。这时候线程堆栈与对象头的状态如下图所示。

如果这个更新操作失败了,那就意味着至少存在一条线程与当前线程竞争获取该对象的锁。虚拟机首先会检查对象的Mark Word是否指向当前线程的栈帧,如果是,说明当前线程已经拥有了这个对象的锁,那直接进入同步块继续执行就可以了,否则就说明这个锁对象已经被其他线程抢占了。如果出现两条以上的线程争用同一个锁的情况,那轻量级锁就不再有效,必须要膨胀为重量级锁,锁标志的状态值变为“10”,此时Mark Word中存储的就是指向重量级锁(互斥量)的指针,后面等待锁的线程也必须进入阻塞状态。

轻量级锁:轻量级锁能提升程序同步性能的依据是“对于绝大部分的锁,在整个同步周期内都是不存在竞争的”这- -经验法则。如果没有竞争,轻量级锁便通过CAS操作成功避免了使用互斥量的开销;但如果确实存在锁竞争,除了互斥量的本身开销外,还额外发生了CAS操作的开销。因此在有竞争的情况下,轻量级锁反而会比传统的重量级锁更慢。

5. 偏向锁

偏向锁:目的是消除数据在无竞争情况下的同步原语,进一步提高程序的运行性能。偏向锁就是在无竞争的情况下把整个同步都消除掉,连CAS操作都不去做了。

偏向锁中的“偏”,就是偏心的“偏”、偏袒的“偏”。它的意思是这个锁会偏向于第一个获得它的线程,如果在接下来的执行过程中,该锁一直没有被其他的线程获取,则持有偏向锁的线程将永远不需要再进行同步

如果读者理解了前面轻量级锁中关于对象头MarkWord与线程之间的操作过程,那偏向锁的原理就会很容易理解。假设当前虚拟机启用了偏向锁(启用参数-XX: +UseBiased Locking,这是自JDK 6起HotSpot虚拟机的默认值),那么当锁对象第一次 被线程获取的时候,虛拟机将会把对象头中的标志位设置为“01”、把偏向模式设置为“1”,表示进入偏向模式。同时使用CAS操作把获取到这个锁的线程的ID记录在对象的M ark Word之中。如果CAS操作成功,持有偏向锁的线程以后每次进入这个锁相关的同步块时,虚拟机都可以不再进行任何同步操作(例如加锁、解锁及对MarkWord的更新操作等)。

一旦出现另外一个线程去尝试获取这个锁的情况,偏向模式就马上宣告结束。根据锁对象目前是否处于被锁定的状态决定是否撤销偏向( 偏向模式设置为“0”),撤销后标志位恢复到未锁定(标志位为“01”)或轻量级锁定(标志位为“00”)的状态,后续的同步操作就按照上面介绍的轻量级锁那样去执行。偏向锁、轻量级锁的状态转化及对象MarkWord的关系如图13-5所示。

因此,当一个对象已经计算过一致性哈希码后,它就再也无法进入偏向锁状态了;而当一个对象当前正处于偏向锁状态,又收到需要计算其一致性哈希码请求1时,它的偏向状态会被立即撤销,并且锁会膨胀为重量级锁。在重量级锁的实现中,对象头指向了重量级锁的位置,代表重量级锁的ObjectMonitor类里有字段可以记录非加锁状态(标志位为“01”)下 的M ark Word,其中自然可以存储原来的哈希码。

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

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

相关文章

Websocket 替代方案:如何使用 Firestore 监听实时事件

大家好,我是CodeQi! 一位热衷于技术分享的码仔。 ​在现代 Web 开发中,实时更新功能对于许多应用程序(如聊天应用、协作工具和在线游戏)都是必不可少的。虽然 WebSocket 是一种常用的实时通信技术,但 Google 的 Firestore 也提供了一种强大的替代方案,使得实时监听变得…

AdaBoost集成学习算法理论解读以及公式为什么这么设计?

本文致力于阐述AdaBoost基本步骤涉及的每一个公式和公式为什么这么设计。 AdaBoost集成学习算法基本上遵从Boosting集成学习思想,通过不断迭代更新训练样本集的样本权重分布获得一组性能互补的弱学习器,然后通过加权投票等方式将这些弱学习器集成起来得到…

解析MySQL的数据类型:理解每种类型及其应用

MySQL是一种流行的关系型数据库管理系统,被广泛应用于Web应用开发中。在数据库设计的过程中,选择合适的数据类型至关重要,因为它不仅影响存储效率和数据完整性,还影响数据库操作的性能和查询速度。本文将详细介绍MySQL支持的各种数…

飞跃边界,尽在掌握 —— Jump Desktop 8 for Mac,远程工作新体验!

Jump Desktop 8 for Mac 是一款强大的远程桌面控制软件,专为追求高效工作与生活平衡的用户设计。它允许您轻松地从Mac设备上远程访问和控制另一台电脑或服务器,无论是跨房间、跨城市还是跨国界,都能实现无缝连接,仿佛操作就在眼前…

【Python实战因果推断】28_倾向分8

目录 Treatment Is Easy to Model Treatment Is Easy to Model 第一个例子中,治疗分配的模型相当容易建立,但干预结果的模型却比较复杂。具体来说,干预遵循伯努利分布,其概率由以下倾向得分给出: 如果您没有意识到&a…

单对以太网:工业4.0时代的通信革命

单对以太网连接器概述 单对以太网(Single Pair Ethernet,简称SPE)是一种新兴的以太网技术,它通过一对双绞线实现数据传输,支持PoDL(Power over Data Line)技术,为终端设备提供电力供…

PTA - 编写函数计算圆面积

题目描述: 1.要求编写函数getCircleArea(r)计算给定半径r的圆面积,函数返回圆的面积。 2.要求编写函数get_rList(n) 输入n个值放入列表并将列表返回 函数接口定义: getCircleArea(r); get_rList(n); 传入的参数r表示圆的半径&#xff0c…

PTA - sdut-使用函数求a+aa+aaa++⋯+aa.....aaa(n个a)之和

题目描述: 给定两个均不超过9的正整数a和n,要求:编写函数fn(a,n), 求aaaaaa⋯aa⋯aa(n个a)之和,fn须返回的是数列之和。 函数接口定义: def fn(a,n):其中, a 和 n 都是传入的参数…

Java项目:基于SSM框架实现的农家乐信息管理平台含前后台【ssm+B/S架构+源码+数据库+答辩PPT+开题报告+毕业论文】

一、项目简介 本项目是一套基于SSM框架实现的农家乐信息管理平台 包含:项目源码、数据库脚本等,该项目附带全部源码可作为毕设使用。 项目都经过严格调试,eclipse或者idea 确保可以运行! 该系统功能完善、界面美观、操作简单、功…

linux信息收集与提权

目录 版本信息收集 kali得一些exp网站 kali自带的searchsploit工具 脏牛提权漏洞(改写没有写权限的文件) 测试靶场下载链接 sudo提权 上传恶意C脚本进行编译生成dirty的elf文件,也可以在攻击机编译好上传 启动,123456是设…

微信小程序毕业设计-教育培训系统项目开发实战(附源码+论文)

大家好!我是程序猿老A,感谢您阅读本文,欢迎一键三连哦。 💞当前专栏:微信小程序毕业设计 精彩专栏推荐👇🏻👇🏻👇🏻 🎀 Python毕业设计…

低资源低成本评估大型语言模型(LLMs)

随着新的大型语言模型(LLMs)的持续发展,从业者发现自己面临着众多选择,需要从数百个可用选项中选择出最适合其特定需求的模型、提示[40]或超参数。例如,Chatbot Arena基准测试平台积极维护着近100个模型,以…

WPF 初识依赖属性

依赖属性的意义和作用 核心模块内存共享,节省空间数据绑定、样式、模板、动画。。。。如果没有依赖属性,这个框架就是一个控件框架 相当于Winform 依赖属性的基本定义 基本过程:声明、注册、包装 在需要写依赖属性的类中,继承…

Clickhouse的联合索引

Clickhouse 有了单独的键索引,为什么还需要有联合索引呢?了解过mysql的兄弟们应该都知道这个事。 对sql比较熟悉的兄弟们估计看见这个联合索引心里大概有点数了,不过clickhouse的联合索引相比mysql的又有些不一样了,mysql 很遵循最…

谷粒商城 - 编写一个自定义校验注解

目录 开始 未来实现效果 第一步:编写自定义校验注解 第二步:编写自定义校验器 第三步:编写配置文件 效果演示 开始 未来实现效果 编写一个 ListValue 注解,可以实现功能有: 限定字段的值,例如指定只…

鸿蒙开发:Universal Keystore Kit(密钥管理服务)【密钥协商(ArkTS)】

密钥协商(ArkTS) 以协商密钥类型为X25519 256,并密钥仅在HUKS内使用为例,完成密钥协商。 开发步骤 生成密钥 设备A、设备B各自生成一个非对称密钥,具体请参考[密钥生成]或[密钥导入]。 密钥生成时,可指定参数HUKS_TAG_DERIVE…

【BUG】RestTemplate发送Post请求后,响应中编码为gzip而导致的报错

BUG描述 20240613-09:59:59.062|INFO|null|810184|xxx|xxx||8|http-nio-xxx-exec-1|com.xxx.jim.xxx.XXXController.?.?|MSG接收到来自xxx的文件请求 headers:[host:"xxx", accept:"text/html,application/json,application/xhtmlxml,application/xml;q0.9,*…

Redis 实现的延时队列组件

最近看开源看到一个好用的延时队列组件,已经上生产。代码量很少,主要就是利用Redis监听过期键实现的。然后搞点策略模式柔和柔和。利用Spring Start 封装了一下,全是俺掌握的知识,稍微研究了下就搞懂了。觉得挺有用的,…

2024.7.9作业

1、提示并输入一个字符串&#xff0c;统计该字符串中字母、数字、空格以及其他字符的个数 #include <stdio.h> #include <string.h> int main(int argc,const char *argv[]) { char arr[30]{0}; int zm0,kg0,sz0,qt0; printf("请输入字符串&…