JUC并发编程之Synchronized锁优化

目录

1. Java对象头

 2. Synchronized锁优化

2.1 偏向锁

2.2 轻量级锁

 2.3 重量级锁

2.4 各种锁对比

1. Java对象头

HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。

对象头是对象在内存中的元数据信息,它包含了对象的一些重要信息,如对象的锁状态、类元数据指针、数组长度等。对象头是Java虚拟机(JVM)管理和操作对象的关键部分。

Java对象头通常包括以下信息:

  1. Mark Word(标记字):Mark Word是对象头中最重要的部分,占据了对象头的大部分空间。它包含了对象的哈希码、锁信息、垃圾回收信息等。Mark Word的具体结构因JVM实现而异,通常包括以下内容:

    • 对象标志位:用于标识对象的状态,例如是否被锁定、是否已经被回收等。
    • 哈希码:用于支持hashCode方法,以及在哈希表中查找对象的位置。
    • 分代年龄:用于垃圾回收的分代算法,标记对象所属的年代。
    • 锁信息:用于支持同步操作,包括偏向锁、轻量级锁和重量级锁的状态信息。
  2. 类型指针:类型指针指向对象的类元数据,它用于确定对象所属的类,以支持对象的方法调用和字段访问。

  3. 数组长度(仅对数组对象有效):如果对象是数组,对象头中会包括数组长度信息。

对象头的结构和大小可能会因不同的JVM实现和对象类型而异。对象头通常占用一定的内存空间,因此它会增加每个对象的内存开销。对象头的信息对于垃圾回收、同步和虚拟机运行时的对象操作非常重要。其中Mark Word结构如下图所示。

 2. Synchronized锁优化

jdk1.6之前,synchronized属于重量级锁(悲观锁) ,jdk1.6之后被进行了大幅度优化,支持锁升级制度缓解加锁和解锁造成的性能费,锁的级别采用: 偏向锁 -> 轻量级锁 -> 重量级锁。

  • 原子性: synchronized依靠两个字节码指令monitorentermonitorexit,可以保证被synchronized修饰的代码在同一时间只能被一个线程访问

  • 可见性: JMM(Java内存模型)规定,内存主要分为主内存和工作内存两种,每个线程拥有不同的工作内存,线程工作时会从主内存中拷贝一份变量到工作内存中。代码执行后,有时工作内存中的变量无法及时刷新到主内存中,或者工作内存无法及时获取主内存的最新值,导致共享变量在不同线程间处于不可见性,由此JMM对synchronized做了2条规定:

    a.线程解锁前,必须把变量的最新值刷新到主内存中。

    b.线程加锁时,先清空工作内存中的变量值,从主内存中重新获取最新值到工作内存中

  • .有序性: 有时候编译器和处理器为了提升代码效率,会进行指令重排序,但是as-if-serial规定无论怎么重排序,单线程程序的执行结果都不能被改变,而synchronized保证了被修饰的程序在同一时间内只能被同一线程访问, 所以其也算是保证了有序性,但synchronized实际上并不是禁止了被修饰的代码指令重排序。

2.1 偏向锁

偏向锁的思想是,如果一个线程获得了锁,那么锁就进入偏向模式,此时,Mark Word的结构也变为偏向锁结构,当这个线程再次请求锁时,无需再做任何同步操作即可再次获取锁,这样就省去了大量有关锁申请的操作,从而也就提供程序的性能。所以对于没有锁竞争的场合,偏向锁有很好的优化效果,但是在有多线程竞争锁的场合,偏向锁就失效了,这种场合下不应该使用偏向锁,否则会得不偿失,偏向锁失败后,将会优先升级为轻量级锁 基本工作过程:
当线程A访问代码块并获取锁对象时,会通过CAS在Mark Word中记录偏向的锁的threadID,因为偏向锁不会主动释放锁,因此以后再次获取锁的时候,需要比较当前线程的 threadID 和 Mark Word 中的threadID是否一致,如果一致,则无需使用CAS来加锁、解锁;如果不一致,则是因为有其他线程如线程b 来竞争该锁,而偏向锁时不会主动释放锁,因此 Mark Word 存储的还是 线程a 的threadID,那么需要查看 Mark Word 中记录的 线程a 是否存活,如果没有存活,那么锁对象被重置为无锁状态,线程b 可以竞争将其设置为偏向锁;如果存活,那么立刻查找线程a的栈帧信息,如果还是需要继续持有这个锁, 那么暂停当前线程a,撤销偏向锁,升级为轻量级锁,如果 线程不再使用该锁,那么将锁状态设为无锁状态,重新偏向新的线程。

在java中偏向锁是默认开启的,绝大多数 情况下,对于加锁的程序大多都会有两个以上的线程去竞争,如果开启偏向锁,反而会加剧锁的资源消耗,可以通过jvm参数启动或关闭偏向锁:

-XX:-UseBiasedLocking = false
    //偏向锁的启动延迟默认为5秒,可以取消这个延迟:
XX:BiasedLockingStartUpDelay=0

2.2 轻量级锁

当多个线程竞争同一个锁时,偏向锁将转化为轻量级锁。轻量级锁通过CAS(Compare and Swap)操作来尝试获取锁,而不会让线程阻塞。如果CAS操作成功,线程获得锁;否则,线程将升级为重量级锁。轻量级锁是由偏向锁升级而来,它考虑的情况是竞争锁的线程不多,而且线程持有锁的时间也不长的情景。轻量级锁能够提升程序性能的依据是“对绝大部分的锁,在整个同步周期内都不存在竞争”。轻量级锁加锁流程如下图所示。

 

 2.3 重量级锁

当轻量级锁无法满足需求,多个线程仍然竞争同一个锁时,锁会升级为重量级锁。在这种情况下,线程将阻塞,直到获取锁。

2.4 锁消除

锁消除是一种Java虚拟机(JVM)和编译器进行的优化技术,用于自动消除不必要的锁操作,以提高程序的性能。锁消除通常用于优化多线程程序中的同步操作。如果编译器确定某个锁的作用域在程序中是局限的,即锁只在某个特定的线程范围内使用,那么它就有可能被消除。代码示例如下:

public class test {

    public static void main(String[] args) {
        int count=0;
        for(int i=0;i<100;i++){
            Object ob=new Object();
            synchronized (ob){
                count++;
            }
        }
    }
}

2.5 各种锁对比

参考:
链接:https://juejin.cn/post/7292955463955906560

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux - 进程状态 - Linux 当中的进程状态是如何维护的?

进程状态 一个进程在 系统当中有很多的状态&#xff0c;比如&#xff1a;一个进程正在被cpu执行&#xff0c;那这个进程就是一个 r 状态&#xff1b;一个进程已经准备好了&#xff0c;但是其中的运行这个进程需要的资源没有准备好&#xff0c;那么这个进程一人不能运行。 比如…

图解java.util.concurrent并发包源码系列——深入理解ConcurrentHashMap并发容器,看完薪水涨一千

图解java.util.concurrent并发包源码系列——深入理解ConcurrentHashMap并发容器 HashMap简单介绍HashMap在并发场景下的问题HashMap在并发场景下的替代方案ConcurrentHashMap如何在线程安全的前提下提升并发度1.71.8 JDK1.7的ConcurrentHashMap源码JDK1.8的ConcurrentHashMap源…

STM32的BOOT1和BOOT0查找及配置-都有BOOT1引脚的

STM32 BOOT0和BOOT1引脚查找 STM32是有BOO0和BOOT1的&#xff0c;有的芯片原理图没有标注BOOT1&#xff0c;但是可以正在手册查到BOOT0和BOOT1引脚的。 STM32 BOOT配置方式 1&#xff09;主Flash 主Flash起始地址为0x08000000&#xff0c;它指的是STM32内置Flash&#xff0c;通…

TensorFlow学习:使用官方模型和自己的训练数据进行图片分类

前言 教程来源&#xff1a;清华大佬重讲机器视觉&#xff01;TensorFlowOpencv&#xff1a;深度学习机器视觉图像处理实战教程&#xff0c;物体检测/缺陷检测/图像识别 注&#xff1a; 这个教程与官网教程有些区别&#xff0c;教程里的api比较旧&#xff0c;核心思想是没有变…

RabbitMQ的交换机(原理及代码实现)

1.交换机类型 Fanout Exchange&#xff08;扇形&#xff09;Direct Exchange&#xff08;直连&#xff09;opic Exchange&#xff08;主题&#xff09;Headers Exchange&#xff08;头部&#xff09; 2.Fanout Exchange 2.1 简介 Fanout 扇形的&#xff0c;散开的&#xff1…

[LaTeX] [数学符号] \mathbb{1}的各种替代方案:解决在 LaTeX 中输入黑板粗体的数字

[LaTeX] [数学符号] \mathbb{1}的各种替代方案&#xff1a;解决在 LaTeX 中输入黑板粗体的数字_latex mathbb-CSDN博客文章浏览阅读5w次&#xff0c;点赞36次&#xff0c;收藏80次。本文介绍如何在 LaTeX 中输入黑板粗体的数字。_latex mathbbhttps://blog.csdn.net/xovee/arti…

ABBYY FineReader PDF15免费版图片文件识别软件

ABBYY全称为“ABBYY FineReader PDF”, ABBYY FineReader PDF集优秀的文档转换、PDF 管理和文档比较于一身。 首先这款软件OCR文字识别功能十分强大&#xff0c;话不多说&#xff0c;直接作比较。下图是某文字识别软件识别一串Java代码的结果&#xff0c;识别的结果就不多评价…

【Qt之控件QTreeView】设置单元格高度、设置图标尺寸

设置列宽 设置高度 自定义代理 继承QItemDelegate&#xff0c;实现sizeHint ()方法&#xff0c;设置自定义委托。 class itemDelegate : public QItemDelegate {Q_OBJECTpublic:explicit itemDelegate(QObject *parent 0) : QItemDelegate(parent){}~itemDelegate(){}virtua…

【JAVA学习笔记】49 - String类,StringBuffer类,StringBuilder类(重要)

项目代码 https://github.com/yinhai1114/Java_Learning_Code/tree/main/IDEA_Chapter13/src/com/yinhai/wrapper_/string_ https://github.com/yinhai1114/Java_Learning_Code/tree/main/IDEA_Chapter13/src/com/yinhai/wrapper_/stringbuffer_ https://github.com/yinhai1114…

Flutter笔记:完全基于Flutter绘图技术绘制一个精美的Dash图标(上)

Flutter笔记 完全基于Flutter绘图技术绘制一个精美的Dart语言吉祥物Dash&#xff08;上&#xff09; 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://…

python基础语法(十一)

目录 文件文件是什么文件路径文件操作1. 打开文件关闭文件写文件读文件 关于中文的处理使用上下文管理器 感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接 &#x1f412;&#x1f412;&#x1f412;个人主页 &#x1f978;&#x1f978;&#x1f978;C语言 &…

MySQL2:MySQL中一条查询SQL是如何执行的?

MySQL2&#xff1a;MySQL中一条查询SQL是如何执行的&#xff1f; MySQL中一条查询SQL是如何执行的&#xff1f;1.连接怎么查看MySQL当前有多少个连接&#xff1f;思考&#xff1a;为什么连接数是查看线程&#xff1f;客户端的连接和服务端的线程有什么关系&#xff1f;MySQL参数…

docker - window Docker Desktop升级

文章目录 前言docker - window Docker Desktop升级 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作不易啊^ _ ^。   而且听说点赞的人每天的运气都不会太差&#xff0c;实在白嫖的话&#xff0c;那欢迎常来…

技术资料MF74:将图像插入单元格注释

【分享成果&#xff0c;随喜正能量】须知往生净土&#xff0c;全仗信、愿。有信、愿&#xff0c;即未得三昧、未得一心不乱&#xff0c;亦可往生。且莫只以一心不乱&#xff0c;及得念佛三昧为志事&#xff0c;不复以信、愿、净念为事。。 我给VBA的定义&#xff1a;VBA是个人…

C++ 运算符

作用域运算符 :: 运算对象&#xff1a; 左边操作数是一个命名空间 &#xff0c;右操作数是命名空间中的标识符 应用 全局作用域 ::name 类作用域 类名::name 命名空间作用域 作用域名::name 三目运算符 C语言返回变量的值C语言是返回变量本身 C三目运算符 返回的是…

2016年上半年上午易错题(软件设计师考试)

以下媒体文件格式中&#xff0c;&#xff08; 12 &#xff09;是视频文件格式。 A &#xff0e; WAV B &#xff0e; BMP C &#xff0e; MP3 D&#xff0e;MOV 以下软件产品中&#xff0c;属于图像编辑处理工具的软件是&#xff08; 13 &#xff09;。 A &#xff0e; Po…

Harmony 个人中心(页面交互、跳转、导航、容器组件)

个人中心 前言正文一、创建工程二、登录① 更换启动页面② 拓展修饰符③ 页面跳转④ 等待进度条 三、导航栏四、首页① 轮播图② 网格列表 五、我的① 带参数跳转 六、源码 前言 今天是1024&#xff0c;祝各位程序员们&#xff0c;钱多事少离家近&#xff0c;不秃也强bug黄。在…

【C】想练习C语言?通讯录的实现了解一下

目录 实现思路 开始实现 添加增加联系人功能 添加显示联系人信息的功能 添加删除联系人功能 添加查找指定联系人的功能 添加修改指定联系人的功能 测试 代码 Test.c Contact.c Contact.h 实现思路 1.通讯录中保存人的信息&#xff1a;名字、年龄、性别、电话、住址…

有关多线程环境下的Volatile、lock、Interlocked和Synchronized们

&#x1f4e2;欢迎点赞 &#xff1a;&#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff0c;赐人玫瑰&#xff0c;手留余香&#xff01;&#x1f4e2;本文作者&#xff1a;由webmote 原创&#x1f4e2;作者格言&#xff1a;新的征程&#xff0c;我们面对的不仅…

Vue插件的使用

一、插件的定义 &#xff08;一&#xff09;创建plugin.js文件 文件名可以自定义&#xff0c;但是行业内默认使用plugin作为文件名&#xff0c;该文件和main.js是平级的。 &#xff08;二&#xff09;编写对象中的install方法 install方法能够接收一个参数&#xff0c;就是…