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://www.mzph.cn/news/869212.shtml

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

相关文章

代码随想录打卡第十八天

代码随想录–二叉树部分 day 17 休息日 day 18 二叉树第五天 文章目录 代码随想录--二叉树部分一、力扣654--最大二叉树二、力扣617--合并二叉树三、力扣700--二乘树中的搜素四、力扣98--验证二叉搜索树 一、力扣654–最大二叉树 代码随想录题目链接:代码随想录 给…

初识CPlusPlus

前言 也是好久没写博客了,那些天也没闲着,去练题去了。实际上练题也可以写练题的博客,但是觉得太简单了些,于是就没有继续写下去。如今又回来写博客,是因为有整理了新的知识C。内容不算多,大多数都是书本上…

证件照片换背景底色 免费 证件照片制作软件免费下载 证件照换衣服软件免费有哪些好用

证件照是我们身份认证的重要凭证,其质量和专业性都很重要。然而,很多时候,由于各种原因,我们可能无法在拍摄证件照时穿上合适的服装,这就给证件照的质量和形象带来了一定的影响。幸运的是,现在市面上出现了…

【保姆级介绍下C语言中的运算符的优先级】

🌈个人主页: 程序员不想敲代码啊 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步! 🧇C语言中的运算符的优先级 🧇C语言中的运算符的优先级决定了表达…

DOM(文档对象模型)生命周期事件

前言 DOM 生命周期事件涉及到从创建、更新到销毁 DOM 元素的不同阶段。 ● 我们来看下当HTML文档加载完再执行JavaScript代码 document.addEventListener(DOMContentLoaded, function (e) {console.log(HTML parsed adn DOM tree built!, e); })● 除此之外,浏览…

单链表(C语言详细版)

1. 链表的概念及结构 概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 链表的结构跟火车车厢相似,淡季时车次的车厢会相应减少,旺季时车次的车厢会额外增加几节。…

Day65 代码随想录打卡|回溯算法篇---组合总和II

题目(leecode T40): 给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次 。 注意:解集不能包含…

Linux文件编程(打开/创建写入读取移动光标)

目录 一、如何在Linux下做开发 1.vi编辑器 2.gcc编译工具 3.常用指令 二、文件打开及创建 三、写入文件 四、读取文件 五、文件“光标”位置 一、如何在Linux下做开发 所谓文件编程,就是对文件进行操作,Linux的文件和Windows系统的文件大差不差…

Python函数 之 函数基础

print() 在控制台输出 input() 获取控制台输⼊的内容 type() 获取变量的数据类型 len() 获取容器的⻓度 (元素的个数) range() ⽣成⼀个序列[0, n) 以上都是我们学过的函数,函数可以实现⼀个特定的功能。我们将学习⾃⼰如何定义函数, 实现特定的功能。 1.函数是什么…

氛围感视频素材高级感的去哪里找啊?带氛围感的素材网站库分享

亲爱的创作者们,大家好!今天我们来聊聊视频创作中至关重要的一点——氛围感。一个好的视频,不仅要有视觉冲击力,还要能够触动观众的情感。那我们应该去哪里寻找这些充满氛围感且高级的视频素材呢?别急,我这…

打开IDEA,程序员思考的永远只有两件事!!!

微信公众号:牛奶 Yoka 的小屋 有任何问题。欢迎来撩~ 最近更新:2024/07/09 [大家好,我是牛奶。] 当年面试时背了很多八股文,但在日渐重复的机械工作中(产品业务开发),计算机网络、操作系统、算…

混合贪心算法求解地铁线路调度

一、问题描述 城市轨道交通的繁荣发展,带来了车辆资源需求的日益增加。如何兼顾运营服务水平和运营成本,以最少的车底优质地完成运输任务成为一大严峻问题。本题在后续的描述中将由多辆动车和拖车组合而成的车组称为车底。在日常的运营组织中&#xff0…

【文档智能】LACE:帮你自动生成文档布局的方法浅尝

前言 往期很多文章都介绍了【文档智能】上布局识别(版式分析)的技术思路,版式分析是通过对文档版式进行布局识别,识别文档中的元素类型的过程。这次来看看一个有趣的思路,通过已有的元素类型,来生成可控的…

赠你一只金色的眼 - 富集分析和表达数据可视化

GOplot包介绍 GOplot包用于生物数据的可视化。更确切地说,该包将表达数据与功能分析的结果整合并进行可视化。但是要注意该包不能用于执行这些分析,只能把分析结果进行可视化。在所有科学领域,由于空间限制和结果所需的简洁性,切…

Agent如何帮助大模型“增强记忆”?

Agent如何帮助大模型“增强记忆”? 原创 格林 神州问学 2024年07月08日 17:50 日本 记忆反馈 >规划? 来源|神州问学 引言 去年6月份,Lilian发布了关于LLM驱动的Agent的结构和组件,其中包括规划、行动、工具还有记忆&#xff…

带有子节点的树状表的父节点拖动排序#Vue3#Sortable插件

带有子节点的树状表的父节点拖动排序#Vue3#Sortable插件 使用Sortable插件这里要保证获取到的是父节点的下标&#xff0c;属性newDraggableIndex获取到的就是只有父节点的下标。设置子节点不能被拖动&#xff0c;最后在逐个调用接口进行数据库中顺序的更新。 <template>…

【Python】已解决:SyntaxError: invalid character in identifier

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决&#xff1a;SyntaxError: invalid character in identifier 一、分析问题背景 在Python编程中&#xff0c;SyntaxError: invalid character in identifier是一个常见的编译…

面经-计算机网络-数据结构-堆

1.什么是堆 堆是一种满足以下条件的树&#xff1a; 堆中的每一个节点值都大于等于&#xff08;或小于等于&#xff09;子树中所有节点的值。或者说&#xff0c;任意一个节点的值都大于等于&#xff08;或小于等于&#xff09;所有子节点的值。 2.堆的用途 当我们只关心所有数…

tk Text文本框赋值,清空

import tkinter as tk# 创建主窗口 root tk.Tk() root.title("文本框内容赋值示例")# 创建一个Text小部件 text_area tk.Text(root, height10, width50) text_area.pack()# 将内容赋值给Text小部件 text_area.insert(tk.END, "这是文本框中的内容。\n")#…

android CameraX构建相机拍照

Android CameraX 是一个 Jetpack 支持库&#xff0c;旨在简化相机应用的开发工作。它提供了一致且易用的API接口&#xff0c;适用于大多数Android设备&#xff0c;并可向后兼容至Android 5.0&#xff08;API级别21&#xff09;。 CameraX解决了在多种设备上实现相机功能时所遇…