synchronized 锁优化原理

news2024/11/27 8:53:15

目录

一、轻量级锁

二、锁膨胀

三、自旋优化

四、偏向锁

五、锁消除


一、轻量级锁

1. 会创建一个锁记录 Lock Record(保存在线程栈中),尝试 CAS 修改 Mark Word 中的对象头,是一种乐观锁的思想,而不是将 Java 对象与操作系统的 Monitor 对象关联起来(重量级锁)

2. CAS 修改

  • mark word 最后两位是 01 表示无锁,最后两位是 00 表示有锁,加锁失败
  • 也有可能是锁的重入(判断对象头的锁记录地址是不是自己),如果是自己执行锁重入,那么再添加一条锁记录 Lock Record 作为锁重入的记录(重入时,锁记录为 null;非重入锁,锁记录是对象头 Mark Word 的值),解锁的时候就是解一次锁去掉一条锁记录,要等栈帧中的所有锁记录被去除才是真的释放了锁

二、锁膨胀

如果在尝试 CAS 替换锁对象的对象头 Mark Word 和锁记录时,替换失败,有种情况就是其他线程对该对象加上了轻量级锁(有竞争),此时就会发生锁膨胀,将轻量级锁升级为重量级锁

  • 加轻量级锁失败,申请 Monitor 锁,让 Object 指向 Monitor,建立 Java 对象和 Monitor 的关联,将 mark word 最后两位变为 10,表示重量级锁
  • 加锁(轻量级锁)失败的线程,加入 Monitor 的阻塞队列
  • 解锁:Thread-0(获取轻量级锁成功的)通过 CAS 将 Mark Word 的值恢复给对象头,由于对象头已经变成了 Monitor 的地址,所以恢复失败,接下来就会走重量级锁的解锁流程,先到 Monitor 中清空 Owner,到阻塞队列唤醒 Thread-1,恢复 Mark Word

三、自旋优化

重量级锁竞争时,线程可以通过自旋来优化,原来需要加入阻塞队列(上下文切换),开销较大,自旋可以重试访问重新判断锁是否可用,自旋成功(在自旋过程中,持有锁的线程退出了同步代码块,释放锁)避免阻塞

  • 自旋会一直消耗 CPU,适用于多核的情况(单核在执行持有锁的线程的任务,自旋线程会被阻塞,没有意义)
  • 问题:可以间隔一段时间再重试吗❓
  • 自旋失败:重试一定次数还是失败就加入阻塞队列
  • Java 6 之后 的自旋锁是自适应的,JVM 底层会根据最近自旋是否成功来判断自旋的次数,最近成功了说明成功概率比较大,就多自旋几次;最近失败了就少重试几次或者不重试;Java 7 之后不能控制是否开启自旋锁,都是由底层来控制是否开启的

四、偏向锁 ‼️

轻量级锁在没有发生竞争时,同一个线程需要重入锁,也需要进行多次 CAS 操作,影响性能

Java 6 中引入的偏向锁来做进一步优化:第一次进行 CAS 操作时,将线程 ID 设置到对象头 Mark Word 中,之后需要重入锁,只需要判断对象头的 ID 是不是自己,不需要进行 CAS 操作

之后只要不发生竞争,这个对象就归该线程所有(问题:如何判断是否发生锁竞争❓锁竞争会将轻量级锁升级为重量级锁,对象头的 Mark Word 会指向 Monitor,释放锁的时候 CAS 失败)

1. 创建对象:如果开启了偏向锁(默认开启),mark word 最后三位是 101,此时 thread、epoch、age 都是 0,但是偏向锁默认是有延迟的,在程序刚启动时不会生效,如果想避免延迟立即生效可以加 JVM 参数;没有开启偏向锁,mark word 最后三位是 001,此时 hashcode、age 都是 0,在第一次用到 hashcode 时才会赋值

问题:创建对象时 101 的意思是已经加了偏向锁还是表示可以加偏向锁❓

2. 加锁:给对象头设置线程 id

3. 释放锁:线程 id 还是保持上一个线程,除非发生锁竞争,这就是偏向锁名字的来由,偏向同一个线程,当该线程再次请求时就不需要再进行复杂的加锁操作

4. 适用场景:单线程多次使用,不适合有多个线程来竞争这把锁的场景,如果知道可能会有冲突,可以通过加 JVM 参数禁用偏向锁,让对象刚创建时是 Normal 正常状态,加锁时后两位是 00(轻量级锁)

5. 加锁顺序:偏向锁 -> 轻量级锁 -> 重量级锁

6. 撤销

  • ⚠️ 注意:调用了 hashcode() 之后就会禁用 / 撤销偏向锁,因为调用 hashcode() 会给 mark word 赋值哈希码,mark word 的大小不够存放线程 id 了,本来可偏向的状态就会被撤销,由 101 变成 001;但是轻量级锁和重量级锁不会有这个问题,因为轻量级锁调用 hashcode() 之后会将哈希码存到锁记录里,重量级锁会存到 monitor 里,解锁时还会还原
  • 释放锁之后其他线程要使用锁:撤销偏向状态(101 -> 001,由可偏向改为不可偏向),将偏向锁升级为轻量级锁(注意不是锁竞争,如果冲突的话是升级为重量级锁了)
  • 调用 wait/notify:也会撤销偏向锁升级为重量级锁,因为 wait/notify 只有重量级锁有

撤销偏向状态比较影响性能:虽然对象被多个线程访问,但并没有发生竞争(t1 释放时候 t2 才访问的),撤销偏向状态升级锁没啥必要,可以将原本偏向 t1 的置为偏向 t2 的(修改 mark word 的线程 id)⬇️

7. 批量重偏向:被多个线程访问但没有发生竞争,修改偏向的线程 id

  • 开启批量重偏向的阈值:当撤销偏向锁的次数达到 20 次之后,JVM 会觉得可能偏向错了,就在加锁时重新偏向加锁线程(第二十次就已经改了)
  • 批量:修改偏向状态是将这批对象的线程 id 都修改成最后一个请求他们锁的线程

8. 批量撤销:撤销偏向达到 40 次(本来就不该偏向),JVM 会对该类的所有对象批量撤销偏向锁,直接进入轻量级锁的状态,新建对象也是 001 不可偏向的

五、锁消除

JVM 的高级优化技术,允许编译器确定锁对象不会引起线程安全问题时,减少不必要的加锁操作,提升程序性能,是 JVM 自动进行的优化,对开发者是透明的

1. JIT 即时编译器会对热点代码(重复调用的)进行优化,如果 synchronized 的对象不会逃离方法的作用范围(局部变量),就可以不加锁,直接消除锁

2. 工作原理

3. 示例场景

  • 如果一个方法内部创建了一个局部变量,对该局部变量进行加锁操作,但是该变量仅存在当前方法栈帧中,不会被其他线程并发访问,所以没有线程安全问题,JVM 就会进行锁消除的优化

4. 优点

  • 性能提升:减少上下文切换和同步开销
  • 简化编程:开发者不需要自己去判断哪些锁是可以避免的,由编译器来自动执行

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

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

相关文章

昇思MindSpore学习笔记4--数据集 Dataset

昇思MindSpore学习笔记4--数据集 Dataset 摘要: 昇思MindSpore数据集Dataset的加载、数据集常见操作和自定义数据集方法。 一、数据集 Dataset概念 MindSpore数据引擎基于Pipeline 数据预处理相关模块: 数据集Dataset加载原始数据,支持文本…

RAG一文读懂!概念、场景、优势、对比微调与项目代码示例

本文结合“基于 ERNIE SDKLangChain 搭建个人知识库”的代码示例,为您讲解 RAG 的相关概念。 01 概念 在2020年 Facebook AI Research(FAIR)团队发表一篇名为《Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks》的论文。这篇论文首次提出了 RA…

C语言力扣刷题4——删除链表的倒数第 N 个结点[双指针],只遍历一遍

力扣刷题4——删除链表的倒数第 N 个结点[双指针] 一、博客声明二、题目描述三、解题思路1、思路说明 四、解题代码(附注释) 一、博客声明 找工作逃不过刷题,为了更好的督促自己学习以及理解力扣大佬们的解题思路,开辟这个系列来记…

动态规划基础练习

我们需要先从数组较大的开始进行处理&#xff0c;每次考察上下左右的&#xff0c;比较当前存储的最大值和转移来的值&#xff0c;哪一个大一点 #define _CRT_SECURE_NO_WARNINGS #include<bits/stdc.h> using namespace std;int n, m; int a[105][105]; int addx[] { 0,…

队列的相关知识

目录 创建 初始化 销毁 头插 尾删 取出头 取出尾 数字个数 判空 队列的性质与特征 性质&#xff1a;一种先进先出的线性表 特征&#xff1a;FIFO&#xff08;先进先出&#xff09; 实现&#xff1a;用数组和链表的都可以 例子&#xff1a;在生产者消费者模型用到了…

比尔盖茨:Agent将是AI最大的赛道

Agent不仅将改变人们与计算机的互动方式&#xff0c;还将颠覆软件行业&#xff0c;引发自从我们从键入命令到点击图标以来计算机领域的最大革命。 保罗艾伦和我一起创立微软的至今&#xff0c;我对软件的热爱至今依然不减。 然而&#xff0c;尽管在过去的几十年中软件已经取得…

vue插槽的简单使用

默认插槽 1.在Category中创建插槽 <slot>默认值<slot/> 2.在App中使用 <Category tittle"美食"> <ul ><li v-for"(l,index) in foods" :key"index">{{l}}</li></ul> </Category> 3.运行后的…

文华缠论笔线段主图指南公式源码去包含

X:10; 笔参数:5; 段参数:6; 笔低A:LOW<LLV(LOW,笔参数),NODRAW; 笔高A:HIGH>HHV(HIGH,笔参数),NODRAW; 笔低:笔低A AND 笔高A0,NODRAW; 笔高:笔高A AND 笔低A0,NODRAW; VP1:BACKSET(笔高,BARSLAST(笔低)1); VP2:BACKSET(笔低,BARSLAST(笔高)1); VP3:(笔低A AND …

全网最详细Gradio教程系列——浏览器集成部署Gradio-Lite

全网最详细Gradio教程系列——浏览器集成Gradio-Lite 前言本篇摘要4 浏览器集成Gradio-Lite4.1 Gradio-Lite介绍4.2 构建Hello World例程4.3 routines4.3.1 multiple files4.3.2 Additional Requirements4.3.3 SharedWorker mode4.3.4 Code and Demo Playground 4.4 与Transfor…

OpenCV学习之cv2.imshow()函数

OpenCV学习之cv2.imshow()函数 一、简介 cv2.imshow 是 OpenCV 库中用于显示图像的基本函数之一。在图像处理和计算机视觉的过程中&#xff0c;使用该函数可以快速预览处理后的图像&#xff0c;便于调试和结果展示。 二、基本语法 cv2.imshow(WindowName, Imgmat)三、参数说…

Webpack: 借助 Babel+TS+ESLint 构建现代 JS 工程环境

概述 Webpack 场景下处理 JavaScript 的三种常用工具&#xff1a;Babel、TypeScript、ESLint 的历史背景、功能以及接入 Webpack 的步骤借助这些工具&#xff0c;我们能构建出更健壮、优雅的 JavaScript 应用 使用 Babel ECMAScript 6.0(简称 ES6) 版本补充了大量提升 JavaSc…

人生最有力,最棒的十句话!

人生最有力&#xff0c;最棒的十句话 1、允许一切事发生&#xff0c;所有一切发生的事不是你能阻挡了的&#xff0c;你接受&#xff0c;他也发生&#xff0c;你不接受&#xff0c;他也发生&#xff0c;你还不如坦然面对接受现实。 2、你焦虑的时候千万不要躺着啥也不干&#xf…

企业数据挖掘平台产品特色及合作案例介绍

泰迪企业数据挖掘平台是一款通用的、企业级、智能化的数据分析模型构建与数据应用场景设计工具&#xff0c;能够一体化地完成数据集成、模型构建、模型发布&#xff0c;为数据分析、探索、服务流程提供支撑&#xff0c;提供完整的数据探索、多数据源接入、特征处理、模型搭建、…

RpcRrovider分发rpc服务(OnMessage和Closure回调)

目录 1.完善rpcprovider.cc的OnConnection 2.完善rpcprovider.cc的OnMessage 3.完整rpcprovider.h 4.完整rpcprovider.cc 这篇文章主要完成&#xff0c;protobuf实现的数据序列化和反序列化。 1.完善rpcprovider.cc的OnConnection rpc的请求是短连接的&#xff0c;请求一次…

MathType2024最新官方无限永久试用版本下载

“我正在使用MathType&#xff0c;它让我的工作变得简单多了。”在中国科学院数学与系统科学研究院的一间办公室内&#xff0c;研究员张益唐兴奋地对《中国科学报》说。 这位因解决了数学界著名的“孪生素数猜想”而名声大噪的数学家&#xff0c;在谈到他最近使用的数学公式编辑…

如何把项目文文件/文件夹)上传到Gitee(全网最细)

目录 1、首先必须要有一个Gitee官网的账号 2、点击右上角的号&#xff0c;点击新建仓库 3、按照下图步骤&#xff0c;自己起仓库名字&#xff0c;开发语言 4、点击初始化readme文件 5、在自己的电脑上选择姚上传的文件夹&#xff0c;或者文件&#xff0c;这里都是一样的&a…

AI与学术的交响:ChatGPT辅助下的实验设计新篇章

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 在学术研究中&#xff0c;实验设计是确保研究质量和结果可信度的关键环节。这篇文章我们将为大家介绍如何利用ChatGPT辅助完成学术论文的实验设计&#xff0c;通过提供灵感、优化实验步…

【docker】2. 编排容器技术发展史(了解)

该篇文章介绍的主要是编排以及容器技术的发展史(了解即可)&#xff0c;如果想单纯学习docker命令操作可直接略过&#xff01;&#xff01;&#xff01; 容器技术发展史 Jail 时代 容器不是一个新概念或者新技术&#xff0c;很早就有了&#xff0c;只是近几年遇到了云计算&am…

昇思25天学习打卡营第4天|扩散模型

文章目录 昇思MindSpore应用实践基于MindSpore的Diffusion扩散模型1、Diffusion Models 简介2、构建 Diffusion Model 的准备工作3、Attention 机制4、条件 U-Net5、Diffusion 正向过程6、Diffusion 反向过程7、Diffusion 模型训练 Reference 昇思MindSpore应用实践 本系列文章…

图形处理单元(GPU)在现代计算中的应用与挑战(研究论文框架)

摘要:随着高性能计算需求的日益增长,图形处理单元(GPU)已从专业的图形渲染处理器转变为具有高性能并行处理能力的多功能计算平台。本文将探讨GPU的核心优势、编程模型、在不同领域的应用以及面临的挑战和限制。此外,还将讨论GPU技术的未来发展趋势和潜在的研究机会。 关键…