当前位置: 首页 > news >正文

jvm实现的锁优化

目录

轻量级锁

轻量级锁的工作流程

轻量级锁的解锁

偏向锁

偏向锁的流程:

偏向锁和轻量级锁机区别:

其他优化

自旋锁和自适应自旋锁

锁消除

锁粗化


轻量级锁

        “轻量级” 是相对于使用操作系统互斥量来实现的传统锁而言的,因此传统的锁机制就被称为“重量级”锁,它的设计初衷是在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。

        首先我们要了解JVM(这里值HotSpot JVM) 中对象头的内存布局。JVM 把对象头分为两部分,第一部分是Mark Word,存储了哈希码(HashCode)、GC分代年龄等。另一部分用于存储指向方法区对象数据类型的指针。Mark Word他是实现轻量级锁和偏向锁的关键。

轻量级锁的工作流程

        在代码即将进入同步块的时候,如果此同步对象没有被锁定(锁标志位为“01”状态),虚拟机首先在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储锁对象的Mark Word的拷贝

        然后,虚拟机将使用CAS操作尝试把对象的Mark Word更新为指向Lock Record的指针。如果CAS成功,那么表示该线程拥有了这个对象的锁,并且将Mark Word 的锁标志位转变为“00”,表示此对象处于轻量级锁定状态。

 如果CAS失败,Mark Word 中已经有了指向锁记录的指针,有两种情况:

一:Mark Word中的指针指向的是当前线程的锁记录,表示发生了轻量级锁重入。这时JVM就会再创建一个锁记录,只不过这个所记录不会记录Mark Word的拷贝,会指向null,表示一次锁重入计数。

二:Mark Word中的指针指向的不是当前线程的锁记录,这时说明发生了锁竞争,那轻量级锁就不再有效,必须要膨胀为重量级锁,锁标志转变为“10”,此时Mark Word 就不再存储锁记录的指针了,而是存储重量级锁互斥量(monitor对象)的指针了。

轻量级锁的解锁

        同样是用CAS来实现的,用锁记录中保存的原Mark Word的值来替换(恢复)当前Mark Word中的值。

轻量级锁能提升同步性能的依据是“对于绝大多数的锁,在整个同步周期内都是不存在竞争的”这一经验法则。如果没有竞争,那么轻量级锁就避免了使用互斥量的开销;但如果存在锁竞争,那么除了互斥量的开销外,还额外发生了CAS的开销。因此再有竞争的情况下,轻量级锁反而回避重量级锁更慢。

偏向锁

顾名思义,他的意思是这个锁会偏向与第一个获得他的线程

偏向锁的流程

        若JVM 启用了偏向锁,那么当锁对象第一次被线程获取的时候,JVM 将会把对象头的标志位设为“01”,并把偏向模式设置为“1”,表示进入偏向模式。同时使用CAS把获得这个锁的线程ID记录再Mark Word(Mark Word的hashCode位置)中如果成功,那么持有偏向锁的线程每次进入的这个锁的同步块的时候,将不再进行任何操作(例如锁重入、解锁、更新Mark Word等)

注意:当一个对象已经计算过一致性哈希码后,那么它就再也无法进入偏向锁状态了;而当一个对象当前正处于偏向锁状态,又收到计算哈希码的请求之后,偏向锁会立即膨胀为重量级锁。因为在重量级锁的ObjectMonitor类中有字段可以记录原来的(非加锁)Mark Word,其中自然可以存储原来的哈希码。

偏向锁和轻量级锁机区别

        偏向锁在轻量级锁的基础上进一步提升了性能。轻量级锁在无竞争的情况下对于每次的加锁请求都使用CAS来避免了互斥量的使用,而偏向锁就是在无竞争的情况下连CAS都不用做了(只是在线程第一次获取偏向锁的时候使用了CAS),通过判断Mark Word中的ThreadID是不是当前线程即可,如不是,则进行重偏向即可。

其他优化

自旋锁和自适应自旋锁

        使用互斥同步来解决线程安全问题时,其中对性能产生很大影响的就是线程阻塞带来的线程上下文文切换,挂起线程和恢复线程都要转入内核态来完成。所以就有了自旋锁的优化:如果物理机器上有多个处理器或处理器多个核心的话,若当前线程第一次获取锁失败,并不会立马进入阻塞,而是会再尝试获取锁几次,我们会让线程执行一个忙循环(自旋)。自适应自选也就是不固定自旋的时间。

锁消除

        锁消除的判断依据主要来源于数据的逃逸分析,如果判断到一段代码中,在堆上的数据都不会逃逸出去被其他线程访问到,那么这些数据就可以当作栈上的数据对待,认为他们是线程私有的,这时就没有必要再加锁了。

锁粗化

        我们通常加锁的时候尽量让同步块中的代码尽可能的少,在存在锁竞争的情况下,可以尽快的拿到锁。但锁的粒度过小的话,有可能出现对同一个对象反复加锁和解锁,甚至加锁操作是在循环体中,这样就导致了很大的性能消耗。类似于这种情况,JVM 就会扩展(粗化)锁的范围。

一些看起来没有加锁的代码,其实隐式的加了很多锁:

public static String concatString(String s1, String s2, String s3) {return s1 + s2 + s3;
}

javap 生成字节码

public static java.lang.String concatString(java.lang.String, java.lang.String, java.lang.String);descriptor: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;flags: ACC_PUBLIC, ACC_STATICCode:stack=2, locals=3, args_size=30: new           #2                  // class java/lang/StringBuilder3: dup4: invokespecial #3                  // Method java/lang/StringBuilder."<init>":()V7: aload_08: invokevirtual #4                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;11: aload_112: invokevirtual #4                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;15: aload_216: invokevirtual #4                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;19: invokevirtual #5                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;22: areturn

String 是一个不可变的类,编译器会对 String 的拼接自动优化。在 JDK 1.5 之前,转化为 StringBuffer 对象的连续 append() 操作,每个 append() 方法中都有一个同步块。反编译后如下:

public static String concatString(String s1, String s2, String s3) {StringBuffer sb = new StringBuffer();sb.append(s1);sb.append(s2);sb.append(s3);return sb.toString();
}

扩展到第一个 append() 操作之前直至最后一个 append() 操作之后,只需要加锁一次就可以。

相关文章:

jvm实现的锁优化

目录 轻量级锁 轻量级锁的工作流程 轻量级锁的解锁 偏向锁 偏向锁的流程&#xff1a; 偏向锁和轻量级锁机区别&#xff1a; 其他优化 自旋锁和自适应自旋锁 锁消除 锁粗化 轻量级锁 “轻量级” 是相对于使用操作系统互斥量来实现的传统锁而言的&#xff0c;因此传统的…...

JMeter做http接口功能测试

1. 普通的以key-value传参的get请求 e.g. 获取用户信息 添加http请求&#xff1b;填写服务器域名或IP&#xff1b;方法选GET&#xff1b;填写路径&#xff1b;添加参数&#xff1b;运行并查看结果。 2. 以Json串传参的post请求 e.g. 获取用户余额 添加http请求&#xff1b;…...

【安全体系架构】——SIEM架构

什么是SIEM架构&#xff1f; 安全信息与事件管理&#xff08;SIEM&#xff09;架构是一种综合性的安全管理系统&#xff0c;旨在监控、检测、报告和应对安全事件和威胁。SIEM系统集成了多个安全功能&#xff0c;包括日志收集、事件管理、威胁检测和响应&#xff0c;以提供组织…...

nginx acess日志找不到访问记录问题

这个是AI给出的可能得原因&#xff1a; 如果在nginx中找不到你的访问记录&#xff0c;但你确实进行了访问并得到了返回&#xff0c;可能有以下原因&#xff1a; 日志文件位置设置不正确&#xff1a;请确保你的nginx配置文件中的access_log指令指向了正确的日志文件路径。日志文…...

canvas使用

canvas使用 1 canvas绘制基本 1 概念 HTML5<canvas>元素用于图形的绘制&#xff0c;区别于css,它的绘制通过javascript来完成绘制的 <canvas>标签只是图形容器&#xff0c;必须使用及保本来绘制图形 Canvas API主要聚焦与2D图形。同时<canvas>元素的Web…...

PMP认证考试证书领取的通知

各位考生&#xff1a; 2022年6月、7月、8月PMI认证考试证书领取工作已经开始&#xff0c;您可通过以下两种方式领取证书&#xff1a; 1.联系本人所在培训机构&#xff0c;通过培训机构向考点统一代领。 2.在2023年10月20日-10月31日内&#xff0c;登录本网站报名系统个人账户…...

华为云HECS云服务器docker环境下安装nacos

华为云HECS云服务器&#xff0c;安装docker环境&#xff0c;查看如下文章。 华为云HECS安装docker-CSDN博客 一、拉取镜像 docker pull nacos/nacos-server二、宿主机创建挂载目录 执行如下命令&#xff1a; mkdir -p /usr/local/nacos/logs mkdir -p /usr/local/nacos/con…...

Oracle数据库修改序列,Oracle中的主键值和序列中的值对应不上时的处理方式

select max(stu.id) maxid from student stu; //查询student表中id的最大值select XXX_SEQ.nextval from dual; //查询student表中id对应序列XXX_SEQ的下一个值alter sequence XXX_SEQ increment by 1000; //将序列XXX_SEQ步长改为1000&#xff0c;对应 student表中id的最大值s…...

Verilog基础:避免混合使用阻塞和非阻塞赋值

相关阅读 Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 “避免在一个always块中混杂阻塞赋值和非阻塞赋值”&#xff0c;这条原则是著名的Verilog专家Cliff Cummings在论文SUNG2000中提出的&#xff0c;这个观点在公众讨…...

04、MySQL-------MyCat实现分库分表

目录 九、MyCat实现分库分表1、分库分表介绍&#xff1a;横向&#xff08;水平&#xff09;拆分**垂直分表**&#xff1a;水平分表&#xff1a;**分库分表** 纵向&#xff08;垂直&#xff09;拆分分表字段选择 2、分库分表操作&#xff1a;1、分析图&#xff1a;2、克隆主从3、…...

开源软件-禅道Zentao

禅道Zentao 简介漏洞复现SQL注入漏洞**16.5****router.class.php SQL注入** **v18.0-v18.3****后台命令执行** 远程命令执行漏洞&#xff08;RCE&#xff09;后台命令执行 简介 是一款开源的项目管理软件&#xff0c;旨在帮助团队组织和管理他们的项目。Zentao提供了丰富的功能…...

Linux生产者消费者模型

生产者消费者模型 生产者消费者模型生产者消费者模型的概念生产者消费者模型的特点生产者消费者模型优点 基于BlockingQueue的生产者消费者模型基于阻塞队列的生产者消费者模型模拟实现基于阻塞队列的生产消费模型 生产者消费者模型 生产者消费者模型的概念 生产者消费者模式就…...

【Qt-20】Qt信号与槽

一、什么是信号和槽 信号是特定情况下被发射的事件&#xff0c;发射信号使用emit关键字&#xff0c;定义信号使用signals关键字&#xff0c;在signals前面不能使用public、private、protected等限定符&#xff0c;信号只用声明&#xff0c;不需也不能对其进行定义实现。另外&am…...

“智能+”时代,深维智信如何借助阿里云打造AI内容生成系统

云布道师 前言&#xff1a; 随着数字经济的发展&#xff0c;线上数字化远程销售模式越来越成为一种主流&#xff0c;销售流程也演变为线上视频会议、线下拜访等多种方式的结合。根据 Gartner 报告&#xff0c;到 2025 年 60% 的 B2B 销售组织将从基于经验和直觉的销售转变为数…...

selenium 自动化测试——WebDriver API

控制浏览器 控制浏览器窗口大小&#xff1a;set_window_size()方法 设置全屏模式下运行&#xff1a;maximize_window()方法 from selenium import webdriver from selenium.webdriver.common.by import By import timedriver webdriver.Chrome() driver.get("http://w…...

【实战】学习 Electron:构建跨平台桌面应用

文章目录 一、Electron 简介二、Electron 的优势1. 学习曲线平缓2. 丰富的生态系统3. 跨平台支持4. 开源和社区支持 三、Electron 的使用1. 安装 Node.js2. 安装 Electron3. 创建项目4. 初始化项目5. 安装依赖6. 创建主进程文件7. 创建渲染进程文件8. 打包应用程序9. 运行应用程…...

Python开发之二维数组空缺值的近邻填充

Python开发之二维数组空缺值的填充 1 实现一&#xff0c;任意位置填充2 实现二&#xff0c;填充内部3 实现三&#xff0c;只填充边缘&#xff0c;不包括四个角 前言&#xff1a;主要实现二维数据里面某一个数据的缺失&#xff0c;用缺失的近邻数据进行均值填充&#xff0c;可以…...

vue使用pdf 导出当前页面,(jspdf, html2canvas )

需要安装两个插件 npm install html2canvas jspdfyarn add html2canvas jspdf<div class"app-container" id"pdfPage"><!--这个放你需要导出的内容--> </div><el-button size"mini" click"onExportPdf">导出…...

【oracle删除表 回滚操作】

oracle数据回滚 oracle表在被误删后&#xff0c;一定时间内&#xff0c;可以采取以下方法进行恢复: 1、先查询数据库当前时间 select to_char(sysdate,‘yyyy-mm-dd hh24:mi:ss’) from dual;2、通过当前时间往前推时间&#xff0c;选择想要恢复的时间点 select * from 表名…...

Vue3 + TypeScript

Vue3 TS开发环境创建 1. 创建环境 vite除了支持基础阶段的纯TS环境之外&#xff0c;还支持 Vue TS开发环境的快速创建, 命令如下&#xff1a; $ npm create vitelatest vue-ts-pro -- --template vue-ts 说明&#xff1a; npm create vitelatest 基于最新版本的vite进行…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:

一、属性动画概述NETX 作用&#xff1a;实现组件通用属性的渐变过渡效果&#xff0c;提升用户体验。支持属性&#xff1a;width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项&#xff1a; 布局类属性&#xff08;如宽高&#xff09;变化时&#…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具

文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台

🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...

嵌入式学习笔记DAY33(网络编程——TCP)

一、网络架构 C/S &#xff08;client/server 客户端/服务器&#xff09;&#xff1a;由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序&#xff0c;负责提供用户界面和交互逻辑 &#xff0c;接收用户输入&#xff0c;向服务器发送请求&#xff0c;并展示服务…...

力扣热题100 k个一组反转链表题解

题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...

scikit-learn机器学习

# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...

解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist

现象&#xff1a; android studio报错&#xff1a; [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决&#xff1a; 不要动CMakeLists.…...