Synchronized同步锁的优化方法 待完工

Synchronized 和后来出的这个lock锁的区别

在并发编程中,多个线程访问同一个共享资源时,我们必须考虑如何维护数据的原子性。在
JDK1.5 之前,Java 是依靠 Synchronized 关键字实现锁功能来做到这点的。Synchronized 是 JVM 实现的一种内置锁,锁的获取和释放是由 JVM 隐式实现。

到了 JDK1.5 版本,并发包中新增了 Lock 接口来实现锁功能,它提供了与 Synchronized
关键字类似的同步功能,只是在使用时需要显示获取和释放锁

Lock 同步锁是基于 Java 实现的,而 Synchronized 是基于底层操作系统的 Mutex Lock
实现的,每次获取和释放锁操作都会带来用户态和内核态的切换,从而增加系统性能开销

因此,在锁竞争激烈的情况下,Synchronized 同步锁在性能上就表现得非常糟糕,它也常
被大家称为重量级锁。

1.6以后呢对这个Synchronized 锁进行了升级,引入了锁升级,某些程度上来说呢。再某些业务场景已经超过了lock。

这里再次生明Synchronized 是关键字,而lock是通过是西安这个lock接口来实现这个所功能的。

Synchronized 底层原理 ,也就是他的同步原理

通常 Synchronized 实现同步锁的方式有两种,一种是修饰方法,一种是修饰方法块。以
下就是通过 Synchronized 实现的两种同步方法加锁的方式:

 javac -encoding UTF-8 SyncTest.java // 先运行编译 class 文件命令

javap -v SyncTest.class // 再通过 javap 打印出字节文件

通过以上命令去反编译出这个文件的字节码文件可以看到

你会发现:Synchronized 在修饰同步代码块时,是由 monitorenter和 monitorexit 指令来实现同步的。进入 monitorenter 指令后,线程将持有 Monitor 对象,退出 monitorenter 指令后,线程将释放该 Monitor 对象。注意修饰的代码块

而同步方法的字节码中,你会发现:当 Synchronized 修饰同步方法时,并没有发
monitorenter 和 monitorexit 指令,而是出现了一个 ACC_SYNCHRONIZED 标志。

这是因为 JVM 使用了 ACC_SYNCHRONIZED 访问标志来区分一个方法是否是同步方法

当方法调用时,调用指令将会检查该方法是否被设置 ACC_SYNCHRONIZED 访问标志。
如果设置了该标志,执行线程将先持有 Monitor 对象,然后再执行方法。在该方法运行期
间,其它线程将无法获取到该 Mointor 对象,当方法执行完成后,再释放该 Monitor 对
象。

 再来看看 Synchronized 修饰方法是怎么实现锁原理的。

JVM 中的同步是基于进入和退出管程(Monitor)对象实现的。每个对象实例都会有一个
Monitor,Monitor 可以和对象一起创建、销毁。

当多个线程同时访问一段同步代码时,多个线程会先被存放在 EntryList 集合中,处于
block 状态的线程,都会被加入到该列表。接下来当线程获取到对象的 Monitor 时,
Monitor 是依靠底层操作系统的 Mutex Lock 来实现互斥的,线程申请 Mutex 成功,则持
有该 Mutex,其它线程将无法获取到该 Mutex。

注意阅读下图

 如果线程调用 wait() 方法,就会释放当前持有的 Mutex,并且该线程会进入 WaitSet 集合
中,等待下一次被唤醒。如果当前线程顺利执行完方法,也将释放 Mutex。

这里插播一下 wait和sleep都释放锁码?好像写代码的时候遇到过

 因 Monitor 是依赖于底层的操作系统实现,存在用户态与内核态之间的切换,所以增加了性能开销。

锁升级优化

为了提升性能,JDK1.6 引入了偏向锁、轻量级锁、重量级锁概念,来减少锁竞争带来的上
下文切换,而正是新增的 Java 对象头实现了锁升级功能。
当 Java 对象被 Synchronized 关键字修饰成为同步锁后,围绕这个锁的一系列升级操作都
将和 Java 对象头有关。

Java 对象头

在 JDK1.6 JVM 中,对象实例在堆内存中被分为了三个部分:对象头、实例数据和对齐填
充。其中 Java 对象头由 Mark Word、指向类的指针以及数组长度三部分组成

Mark Word 记录了对象和锁有关的信息。Mark Word 在 64 位 JVM 中的长度是 64bit

 锁升级功能主要依赖于 Mark Word 中的锁标志位和释放偏向锁标志位,Synchronized 同
步锁就是从偏向锁开始的,随着竞争越来越激烈,偏向锁升级到轻量级锁,最终升级到重量
级锁。

1. 偏向锁

偏向锁主要用来优化同一线程多次申请同一个锁的竞争。在某些情况下,大部分时间是同一
个线程竞争锁资源,例如,在创建一个线程并在线程中执行循环监听的场景下,或单线程操
作一个线程安全集合时,同一线程每次都需要获取和释放锁,每次操作都会发生用户态与内
核态的切换。

 再自己的同步代码块里加锁,同步代码块有全局变量,我们枷锁,让它不被别的线程修改

偏向锁的作用就是,当一个线程再次访问这个同步代码或方法时,该线程只需去对象头的
Mark Word 中去判断一下是否有偏向锁指向它的 ID,无需再进入 Monitor 去竞争对象
了。

当对象被当做同步锁并有一个线程抢到了锁时,锁标志位还是 01,“是否偏向锁”标
志位设置为 1,并且记录抢到锁的线程 ID,表示进入偏向锁状态。

一旦出现其它线程竞争锁资源时,偏向锁就会被撤销。偏向锁的撤销需要等待全局安全点,
暂停持有该锁的线程,同时检查该线程是否还在执行该方法,如果是,则升级锁,反之则被
其它线程抢占。

下图中红线流程部分为偏向锁获取和撤销流程:

偏向锁这个设计到一个调优 高并发

在高并发场景下,当大量线程同时竞争同一个锁资源时,偏向锁就会被撤销,发生
stop the world 后, 开启偏向锁无疑会带来更大的性能开销,这时我们可以通过添加 JVM
参数关闭偏向锁来调优系统性能

如果你确定应用程序里所有的锁通常情况下处于竞争状态,可以通过JVM参数关闭偏向锁:-XX:-
UseBiasedLocking=false,那么程序默认会进入轻量级锁状态。

2.轻量级锁

(1)轻量级锁加锁

        线程在执行同步块之前,JVM会先在当前线程的栈桢中创建用于存储锁记录的空间,并
将对象头中的Mark Word复制到锁记录中,官方称为Displaced Mark Word。然后线程尝试使用
CAS将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失
败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。

(2)轻量级锁解锁

轻量级解锁时,会使用原子的CAS操作将Displaced Mark Word替换回到对象头,如果成
功,则表示没有竞争发生。如果失败,表示当前锁存在竞争,锁就会膨胀成重量级锁。图2-2是
两个线程同时争夺锁,导致锁膨胀的流程图。

 因为自旋会消耗CPU,为了避免无用的自旋(比如获得锁的线程被阻塞住了),一旦锁升级
成重量级锁,就不会再恢复到轻量级锁状态。当锁处于这个状态下,其他线程试图获取锁时,
都会被阻塞住,当持有锁的线程释放锁之后会唤醒这些线程,被唤醒的线程就会进行新一轮
的夺锁之争。

这里非常重要的一点就是

当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID

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

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

相关文章

论文阅读 RRNet: A Hybrid Detector for Object Detection in Drone-captured Images

文章目录 RRNet: A Hybrid Detector for Object Detection in Drone-captured ImagesAbstract1. Introduction2. Related work3. AdaResampling4. Re-Regression Net4.1. Coarse detector4.2. Re-Regression 5. Experiments5.1. Data augmentation5.2. Network details5.3. Tra…

NeRF室内重建对比:Nerfstudio vs. Luma AI vs. Instant-NGP

十年前,Matterport 改变了房地产业,让房地产买家可以进行数字旅游。 买家可以在房产内从一个点移动到另一个点并环顾四周。 与 2D 照片库相比,这是一个巨大的改进。 然而,买家仍然被房产内的一系列问题所困扰。 推荐:用…

rk3399移植linux kernel

rk3399移植linux kernel 0.前言一、移植ubuntu根文件系统二、移植linux1.支持NFS(可选)2.配置uevent helper3.支持etx4文件系统(默认已支持)4.配置DRM驱动5.有线网卡驱动6.无线网卡驱动 三、设备树四、内核镜像文件制作五、烧录六、总结 参考文章: 1.RK3399移植u-bo…

TypeScript 中【class类】与 【 接口 Interfaces】的联合搭配使用解读

导读: 前面章节,我们讲到过 接口(Interface)可以用于对「对象的形状(Shape)」进行描述。 本章节主要介绍接口的另一个用途,对类的一部分行为进行抽象。 类配合实现接口 实现(impleme…

如何用正确的姿势监听Android屏幕旋转

作者:37手游移动客户端团队 背景 关于个人,前段时间由于业务太忙,所以一直没有来得及思考并且沉淀点东西;同时组内一个个都在业务上能有自己的思考和总结,在这样的氛围下,不由自主的驱使周末开始写点东西&…

QT生成Debug和Release发布版后,运行exe缺少dll问题

在QT Creator生成debug和release的exe执行文件后,运行时,报错缺少*.dll.解决办法1: 在系统环境变量中添加D:\Qt\Qt5.13.2\Tools\mingw730_64\bin后,即可运行。 当使用此方法时,将exe拷贝到其他电脑中运行时&#xff0c…

软件性能测试有哪些测试指标?性能测试报告对软件产品起到的作用

在软件开发过程中,性能测试是一个至关重要的环节,主要关注软件系统在不同负载条件下的表现,以评估其稳定性、可扩展性和响应能力。它可以帮助开发人员评估软件系统的质量和性能。 一、软件性能测试的测试指标 性能测试的测试指标直接影响着…

【代码解读】RRNet: A Hybrid Detector for Object Detection in Drone-captured Images

文章目录 1. train.py2. DistributedWrapper类2.1 init函数2.2 train函数2.3 dist_training_process函数 3. RRNetOperator类3.1 init函数3.1.1 make_dataloader函数 3.2 training_process函数3.2.1 criterion函数 4. RRNet类(网络模型类)4.1 init函数4.…

计算机视觉--距离变换算法的实战应用

前言: Hello大家好,我是Dream。 计算机视觉CV是人工智能一个非常重要的领域。 在本次的距离变换任务中,我们将使用D4距离度量方法来对图像进行处理。通过这次实验,我们可以更好地理解距离度量在计算机视觉中的应用。希望大家对计算…

IPC之一:使用匿名管道进行父子进程间通信的例子

IPC 是 Linux 编程中一个重要的概念,IPC 有多种方式,本文主要介绍匿名管道(又称管道、半双工管道),尽管很多人在编程中使用过管道,但一些特殊的用法还是鲜有文章涉及,本文给出了多个具体的实例,每个实例均附…

CentOS 7 构建 LVS-DR 群集 nginx负载均衡

1、基于 CentOS 7 构建 LVS-DR 群集。 DS(Director Server):DIP 192.168.231.132 & VIP 192.168.231.200 [root132 ~]# nmcli c show NAME UUID TYPE DEVICE ens33 c89f4a1a-d61b-4f24-a260…

AIGC:【LLM(四)】——LangChain+ChatGLM:本地知识库问答方案

文章目录 一.文件加载与分割二.文本向量化与存储1.文本向量化(embedding)2.存储到向量数据库 三.问句向量化四.相似文档检索五.prompt构建六.答案生成 LangChainChatGLM项目(https://github.com/chatchat-space/langchain-ChatGLM)实现原理如下图所示 (与基于文档的问答 大同小…

Python连接Hive实例教程

一 Python连接hive环境实例 经在网络查询相关的教程,发现有好多的例子,发现连接底层用的的驱动基本都是pyhive和pyhs2两种第三方库的来连接的 hive,下面将简介windows 10 python 3.10 连接hive的驱动程序方式,开发工具:pycharm …

架构实践方法

一、识别复杂度 将主要的复杂度问题列出来,然后根据业务、技术、团队等综合情况进行排序,优先解决当前面临的最主要的复杂度问题。对于按照复杂度优先级解决的方式,存在一个普遍的担忧:如果按照优先级来解决复杂度,可…

List list=new ArrayList()抛出的ArrayIndexOutOfBoundsException异常

1.应用场景,今天生产日志监控到一组new ArrayList() 进行add 异常,具体日志如下: eptionHandler.handler(178): TXXYBUSSINESS|执行异常 java.util.concurrent.CompletionException: java.lang.ArrayIndexOutOfBoundsException: Index 1 out…

银河麒麟QT连接DM8数据库

1. 安装达梦8 官网下载, 按照官方文档进行安装即可. 2. 安装unixodbc 1> 下载odbc安装包 unixODBC-2.3.7pre.tar.gz 2> 解压 tar -xvf unixODBC-2.3.7pre.tar.gz3> 编译 ./configure -prefix /usr/local make && make install4> 查找配置 odbcinst -j5…

【从零学习python 】04. Python编程基础:变量、数据类型与标识符

文章目录 变量以及数据类型一、变量的定义二、变量的类型三、查看数据类型 标识符和关键字标识符命名规则命名规范 关键字进阶案例 变量以及数据类型 一、变量的定义 对于重复使用,并且经常需要修改的数据,可以定义为变量,来提高编程效率。…

代码随想录算法训练营第51天|动态规划part09|198.打家劫舍、213.打家劫舍II、337.打家劫舍III

代码随想录算法训练营第51天|动态规划part09|198.打家劫舍、213.打家劫舍II、337.打家劫舍III 198.打家劫舍 198.打家劫舍 思路: 仔细一想,当前房屋偷与不偷取决于 前一个房屋和前两个房屋是否被偷了。 所以这里就更感觉到&a…

鉴源论坛·观模丨形式化方法的工业应用:轨交领域

作者 | 王依玲 上海控安可信软件创新研究院系统建模组 版块 | 鉴源论坛 观模 社群 | 添加微信号“TICPShanghai”加入“上海控安51fusa安全社区” 引言:前面几期文章介绍了形式化方法的发展历史和具体技术,并从整体的角度介绍了形式化方法的工程化。本…

SpringBoot 的事务及使用

一、事务的常识 1、事务四特性(ACID) A 原子性:事务是最小单元,不可再分隔的一个整体。C 一致性:事务中的方法要么同时成功,要么都不成功,要不都失败。I 隔离性:多个事务操作数据库中同一个记录或多个记录时,对事务进…