JUC:synchronized优化——锁的升级过程(偏向锁->轻量级锁->重量级锁)以及内部实现原理

文章目录

  • 锁的类型
    • 轻量级锁
    • 重量级锁
    • 自旋优化
    • 偏向锁
    • 偏向锁的细节
      • 偏向锁的撤销
      • 批量重偏向
      • 批量撤销
      • 锁消除

锁的类型

重量级锁、轻量级锁、偏向锁。
加锁过程:偏向->轻量级->重量级

轻量级锁

轻量级锁的使用场景:如果一个对象虽然有多线程要加锁,但加锁的时间是错开的(也就是没有竞争),那么可以使用轻量级锁来优化。

轻量级锁对使用者是透明的,即语法仍然是 synchronized,锁的升级什么的不用我们考虑。

static final Object obj = new Object();public static void method1() {synchronized( obj ) {// 同步块 Amethod2();}
}public static void method2() {synchronized( obj ) {// 同步块 B}
}

每一个线程的栈帧中都会包含一个锁记录结构,记录对象头中的markword。

在这里插入图片描述

锁记录中Object reference指向锁对象,并尝试用 cas 交换 Object 的 Mark Word,将Mark Word的值存入锁记录中。

在这里插入图片描述

若cas成功,对象头中存储锁地址和锁状态00(轻量级),表示该线程给此对象加锁。

在这里插入图片描述

如果 cas 失败,有两种情况:

  • 如果是其它线程已经持有了该 Object 的轻量级锁,这时表明有竞争,进入锁膨胀过程。
  • 如果是自己执行了 synchronized 锁重入,那么再添加一条 Lock Record 作为重入的计数。

在这里插入图片描述

当退出 synchronized 代码块(解锁时)如果有取值为 null 的锁记录,表示有重入,这时重置锁记录,表示重入计数减一。

在这里插入图片描述

当退出 synchronized 代码块(解锁时)锁记录的值不为 null,这时使用 cas 将 Mark Word 的值恢复给对象头

  • 成功,则解锁成功。
  • 失败,说明轻量级锁进行了锁膨胀或已经升级为重量级锁,进入重量级锁解锁流程。

重量级锁

如果在尝试加轻量级锁的过程中,CAS操作无法成功,这时一种情况就是有其它线程为此对象加上了轻量级锁(有竞争),这时会进行锁膨胀,将轻量级锁膨胀为重量级锁。

static Object obj = new Object();
public static void method1() {synchronized( obj ) {// 同步块}
}

当 Thread-1 进行轻量级加锁时,Thread-0 已经对该对象加了轻量级锁。

在这里插入图片描述

这时Thread-1就会CAS失败,进入锁膨胀过程。

  • Object 对象申请 Monitor 锁,让 Object 指向重量级锁地址
  • 然后自己进入 Monitor 的 EntryList BLOCKED
  • Object 对象头锁标记变为10(重量级)

在这里插入图片描述

当 Thread-0 退出同步块解锁时,使用 CAS 将 Mark Word 的值恢复给对象头,失败。这时会进入重量级解锁流程,即按照 Monitor 地址找到 Monitor 对象,设置 Owner 为 null,唤醒 EntryList 中 BLOCKED 线程。

简单来说,我们可以简化一下:

  • 就是没竞争时,自己正常加锁运行解锁即可,同一线程有锁的重入,防止没必要的加锁解锁过程。
  • 如果有竞争时,新线程进入阻塞队列等待,当解锁时,唤醒阻塞队列中的线程。

自旋优化

重量级锁竞争的时候,可以使用自旋(不断的循环尝试获取重量级锁)来进行优化,如果当前线程自旋成功(当前持有锁的线程释放了锁),这时当前线程就可以避免阻塞。(阻塞再恢复,会进行上下文切换,耗费性能)

但是自旋也是会消耗性能的,尤其是进程非常多的时候,一堆进程在不断循环等待锁被释放,优点就是及时,一释放锁就能感应到。

偏向锁

在锁重入时,会产生锁记录,每次都需要尝试CAS,虽然会失败,但是CAS这个操作是没必要的。

优化:

将对象头中记录持有该锁的线程id,如果发生锁的重入,检测对象头,若是自己的,那么就不用再CAS了。

对比:

在这里插入图片描述

在这里插入图片描述

偏向锁的细节

在这里插入图片描述

一个对象创建时:

  • 如果开启了偏向锁(默认开启),那么对象创建后,markword 值为 0x05 即最后 3 位为 101,这时它的 thread、epoch、age 都为 0。

  • 偏向锁是默认是延迟的,不会在程序启动时立即生效,如果想避免延迟,可以加 VM 参数 -XX:BiasedLockingStartupDelay=0 来禁用延迟。

  • 如果没有开启偏向锁,那么对象创建后,markword 值为 0x01 即最后 3 位为 001,这时它的 hashcode、age 都为 0,第一次用到 hashcode 时才会赋值。

  • 正常状态对象一开始是没有 hashCode 的,第一次调用才生成。

  • 调用了 hashCode() 后会撤销该对象的偏向锁。

从图中也可以看出,偏向锁的markword没有位置可以放hashcode了,除非转变为轻量级锁,所以调用对象的hashCode会撤销他的偏向锁。

偏向锁的撤销

除了上面说的调用hashCode,也可用 让其他线程使用偏向锁,这时偏向锁会升级为普通锁。

不过两个线程需要错开加锁,不然会升级为重量级锁。

批量重偏向

可用发现,就算错开没用竞争,那么锁也会从偏向锁转变为普通锁,那其实锁的转变也是消耗性能的,所以就有了偏向锁的重偏向这个功能。

如果对象被多个线程访问,但没有竞争(错开),这时偏向了线程 T1 的对象仍有机会重新偏向 T2,重偏向会重置对象的 Thread ID 为 T2线程。

当某对象(这一类的不同对象)撤销偏向锁阈值超过20次后,jvm会觉得,我是不是偏向错了,于是会在给这些对象加锁的时候重新偏向至新加锁线程。

批量撤销

当相同类型不同对象撤销偏向锁阈值超过 40 次后,jvm 会这样觉得,自己确实偏向错了,根本就不该偏向,这个锁竞争太激烈了。于是整个类的所有对象都会变为不可偏向的,新建的该类型对象也是不可偏向的(轻量级)。

锁消除

简单来说,当jvm调用某方法达到一定阈值,就会用记时编译器优化,发现锁加和不加没有影响时,就会去除掉锁。

public class MyBenchmark {static int x = 0;public void a() throws Exception {x++;}public void b() throws Exception {Object o = new Object();synchronized (o) {x++;}}
}

比如Object为局部变量,根本不会逃离此方法作用范围,不能被共享,那加不加锁没啥意义,jvm就会去除掉锁去运行,从而优化性能。

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

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

相关文章

登录者个人信息查询

目录 🥞1.vo层描述 🍿2..vo层创建 🌭3.编写controller层 🥓4.service层 🧂5.测试 1.vo层描述 Spring Boot项目中的实体类通常用于映射数据库表,包含了业务对象的所有属性。然而,前端或其…

Jenkins详细安装配置部署

目录 简介一、安装jdk二、安装jenkins这里如果熟悉 Jenkins ,可以【选择插件来安装】,如果不熟悉,还是按照推荐来吧。注意: 三、插件安装如果上面插件安装,选择的不是【安装推荐的插件】,而是【选择插件来安…

ZYNQ学习之PetaLinux与Vitis的安装

基本都是摘抄正点原子的文章&#xff1a;<领航者 ZYNQ 之嵌入式Linux 开发指南 V3.2.pdf&#xff0c;因初次学习&#xff0c;仅作学习摘录之用&#xff0c;有不懂之处后续会继续更新~ 一、Petalinux安装 1.1、Petalinux资源下载 百度云安装包&#xff1a; Petalinux 安装…

FFMPEG C++封装(一)(C++ FFMPEG)

1 概述 FFMPEG是一个C语言开源视音频编解码库。本文将FFMPG4.1.3进行C封装&#xff0c;形成C FFMPG库。 2 架构 架构图如下所示&#xff1a; 架构说明: Init 初始化FFMPEG库。IStream 输入流&#xff0c;FFMPEG的输入音视频文件。Packet 音视频数据包Decoder 音视频编码器F…

OpenHarmony:RichEditor组件样例开发

使用 richEditor 组件实现一个富文本编辑框&#xff0c;包含富文本编辑区域和功能栏&#xff0c;功能栏中有多个按键&#xff0c;可以调整字体大小、字体样式、字体颜色、布局&#xff0c;并可以插入图片。 api 版本&#xff1a;api11 主页面 import { TitleBar } from ../.…

element跑马灯/轮播图,第一页隐藏左边按钮,最后一页隐藏右边按钮(vue 开箱即用)

图示&#xff1a; 第一步&#xff1a; <el-carousel :class"changeIndex0?leftBtnNone:changeIndeximgDataList.length-1? rightBtnNone:" height"546px" :autoplay"false" change"changeNext"><el-carousel-item v-for…

Stata 15 for Mac:数据统计分析新标杆,让研究更高效!

Stata 是一种统计分析软件&#xff0c;适用于数据管理、数据分析和绘图。Stata 15 for Mac 具有以下功能&#xff1a; 数据管理&#xff1a;Stata 提供强大的数据管理功能&#xff0c;用户可以轻松导入、清洗、整理和管理数据集。 统计分析&#xff1a;Stata 提供了广泛的统计…

A Little Is Enough: Circumventing Defenses For Distributed Learning

联邦学习的攻击方法&#xff1a;LIE 简单的总结&#xff0c;只是为了能快速想起来这个方法。 无目标攻击 例如总共50个客户端&#xff0c;有24个恶意客户端&#xff0c;那么这个时候&#xff0c;他需要拉拢2个良性客户端 计算 50 − 24 − 2 50 − 24 0.923 \frac{50-24-2}{…

瑞_23种设计模式_中介者模式

文章目录 1 中介者模式&#xff08;Mediator Pattern&#xff09;1.1 介绍1.2 概述1.3 中介者模式的结构1.4 中介者模式的优缺点1.5 中介者模式的使用场景 2 案例一2.1 需求2.2 代码实现 3 案例二3.1 需求3.2 代码实现 &#x1f64a; 前言&#xff1a;本文章为瑞_系列专栏之《2…

Java项目:80 springboot师生健康信息管理系统

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 系统的角色&#xff1a;管理员、宿管、学生 管理员管理宿管员&#xff0c;管理学生&#xff0c;修改密码&#xff0c;维护个人信息。 宿管员…

数组类模板(类模拟实现静态数组)

目录 介绍&#xff1a; 案例描述&#xff1a; 思路&#xff1a; 对要求分别分析实现&#xff1a; 创建对应的类&#xff1a; 1.定义一个数组类 2.类中属性有&#xff1a;数组&#xff0c; 容量&#xff0c; 大小 3.数组函数有&#xff1a; 构造函数&#xff08;容量&am…

排序---数组和集合

1、数组排序 Arrays.sort(int[] a)这种形式是对一个数组的所有元素进行排序&#xff0c;并且是按照从小到大的排序。 public static void main(String[] args) {Integer []arr {1,2,3,4,5,6};//升序Arrays.sort(arr);for (int x:arr){System.out.print(x " ");}Sys…

IRIS / Chronicles 定义 Item Response Type 字段属性

Response Type 在关系数据库中可能没有这个选项&#xff0c;我们对关系数据库表中的数据返回的数据就是是数据&#xff0c;通常不再做过多定义。 但是 IRIS 会对返回的数据也做一些定义&#xff0c;这个就是我们说的 Response Type。 Single &#xff08;单一&#xff09; 这…

二维随机变量的条件分布-已知X概率密度,X条件下的Y概率密度求解y的概率密度

问题&#xff1a;设数X在区间(0,1)上随机地取值,当观察到Xx(0<x<1)时,数Y在区间(x,1)上随机地取值.求Y的概率密度f(y)&#xff1f; 求解&#xff1a; 首先&#xff0c;数X在区间(0,1)上均匀分布&#xff0c;因此其概率密度函数fX​(x)为&#xff1a; fX​(x)1 0<…

Unity类银河恶魔城学习记录11-7 p109 Aplly item modifiers源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili ItemData_Equipment.cs using System.Collections; using System.Collecti…

K8S安装和部署(kubeadmin安装1主2从)

这里用kubeadmin方式进行安装部署 1. 准备三台服务器 服务器地址 节点名称 192.168.190.200 master 主 192.168.190.201 node1 从 192.168.190.202 node2 从 2. 主机初始化&#xff08;所有主机&#xff09; 2.1根据规划设置主机名 #切换到192.168.190.200 hostnamectl…

327京东一面

1.项目相关 2.手撕SQL 两道 3.JMeter性能测试 首先&#xff0c;进行基准测试&#xff1a; 单用户测试&#xff08;单用户循环多次得到的数据&#xff09;&#xff1b;为多用户并发执行提供参考 其次&#xff0c;进行负载测试&#xff1a; 通过逐步增加系统负载&#xff0…

大数据学习-2024/3/29-oracle使用介绍

在plsql中登录ORACLE数据。 默认用户&#xff1a; 1、sys&#xff1a; 角色&#xff1a;数据库超级管理员账户。 权限&#xff1a;具有最高的权限&#xff0c;可以执行任何操作&#xff0c;包括操作数据字典和控制文件。可以创建和删除数据库对象&#xff0c;授予和回收其他用户…

Linux系统中安装一些常用的插件备用

Linux系统中安装一些常用的插件备用 1.安装wget yum -y install wget 2.安装vim yum -y install vim-enhanced 3.更换yum源为国内的阿里云源&#xff08;选择&#xff09; 1、备份CentOS-Base.repo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.…

代码随想录算法训练营第二十四天| 理论基础,77. 组合

题目与题解 参考资料&#xff1a;回溯法理论基础 带你学透回溯算法&#xff08;理论篇&#xff09;| 回溯法精讲&#xff01;_哔哩哔哩_bilibili 77. 组合 题目链接&#xff1a;​​​​​​​​​​​​​​77. 组合 代码随想录题解&#xff1a;77. 组合 视频讲解&#xff…