【JavaEE初阶】深入理解不同锁的意义,synchronized的加锁过程理解以及CAS的原子性实现(面试经典题);

前言

🌟🌟本期讲解关于锁的相关知识了解,这里涉及到高频面试题哦~~~

🌈上期博客在这里:【JavaEE初阶】深入理解线程池的概念以及Java标准库提供的方法参数分析-CSDN博客

🌈感兴趣的小伙伴看一看小编主页:GGBondlctrl-CSDN博客

 

目录

📚️1.引言

📚️2.锁的策略

2.1乐观锁与悲观锁

2.2轻量级锁和重量级锁

2.3自旋锁和挂起等待锁

2.4普通互斥锁和读写锁

2.5公平锁和非公平锁

2.6可重入锁和不可重入锁

📚️3.synchronized的加锁过程

3.1锁升级

1.偏向锁阶段

2.轻量级锁

3.重量级锁

3.2锁消除

3.3锁粗化

📚️4.CAS的实现原理

4.1CAS的内部逻辑

4.2CAS实现线程安全

4.3CAS的原子性

📚️5.总结

📚️1.引言

    Hello!uu们小编又来啦,上期在介绍过线程池的理解后,相信大家已经对其有了更深的了解,致此多线程初阶已经完结,前面的博客也可以供大家学习,复习哟~~~

本期只要是讲解关于不同锁的不同的意义理解,例如:乐观锁和悲观锁,以及synchronized的加锁之前的操作.......那就直接开始吧!!!

📚️2.锁的策略

2.1乐观锁与悲观锁

这是锁的两种不同实现方式;

乐观锁:即加锁之前,预估在程序中的锁的冲突不大,因此在加锁的时候就不会进行太多的操作;

悲观锁: 即加锁之前,预估在程序中的锁的冲突很大,因此在加锁的时候就不会进行比较多的操作;

乐观锁的影响: 由于加锁的工作很少,所以加锁的时候就很快,但是缺点就是会造成更多的CPU资源的消耗(引入一些其他问题)

悲观锁的影响:由于加锁的时候工作比较多,所以在加锁的时候就比较满,所以此时造成的问题就很少;

2.2轻量级锁和重量级锁

轻量级锁:消耗的CPU资源多,加锁比较快=>这里理解为乐观锁;

重量级锁:消耗的CPU资源少,加锁比较慢=>这里理解为悲观锁;

这里的轻量级锁和重量级锁是加锁后对锁的一种评价,而乐观锁和悲观锁是加锁前的一种预估,这里是从两种不同的角度来描述一件事情;

2.3自旋锁和挂起等待锁

自旋锁:是轻量级锁的一种典型实现,一般搭配while循环,在加锁成功后退出循环,但是加锁不成功后,会进入循环再次尝试加锁;

挂起等待锁:是重量级锁的一种典型实现,在加锁失败后,会进入阻塞状态,直到获取到锁

自旋锁的使用:一般用于锁冲突比较小的情况,由于高速反复的尝试加锁,导致CPU的资源消耗上升,取而代之的是加锁的速度快,但是在线程多的情况下会发生“线程饿死”的问题

挂起等待锁的使用:一般用于所冲突比较大的情况,由于进入阻塞后,就是内核随机调度来进行执行,要进行的操作增加,导致加锁更慢了

synchronized锁:这里的synchronized锁具有自适应的能力的,例如在锁冲突情况比较严重的时候,这里的synchronized就是悲观锁、重量级锁、挂起等待锁.....所以这里的synchronized是根据当时的锁的冲突情况来进行自适应的~~~

2.4普通互斥锁和读写锁

普通互斥锁:即synchronized类似,只有加锁和解锁

读写锁:这里的解锁是一样的,但是在加锁的时候分为两种即“加读锁”与“加写锁”

这里的情况就是:

读锁和读锁这之间,不会出现锁的冲突

读锁和写锁这之间,会出现锁的冲突

写锁和写锁这之间,会出现锁的冲突

即一个线程加读锁的时候,另一个线程是可以“读”的,但是是不可以“写”的;

即一个现场加写锁的时候,另一个线程是不可以进行“读”和“写”的 

为什么要引入读写锁:

在线程的读的操作中,读这个操作本来就是线程安全的,但是使用synchronized任然要给这一部分要加锁,由于加锁这个操作本来就是一个低效率的操作;在读的过程中不加锁可以打打提升效率;

但是读的时候完全不加锁,可能会在读的时候进行写操作,所以这里又要加“读锁”;

2.5公平锁和非公平锁

公平锁:即等待加锁的时间越久,就应该在锁释放的时候,先加上锁(先来先到原则)

非公平死锁:即在锁释放后,获取锁的概率是一样的,存在竞争;

如下图所示:

2.6可重入锁和不可重入锁

可重入锁:即在加锁过后任然在这个线程继续进行加锁;

不可重入锁:即在加锁过后,这个线程就不能进行加锁了;

例如synchronized是一个可重入锁,但是在系统中的锁是一个不可重入锁;

可重入锁需要记录加锁的对象,以及加锁的次数;

📚️3.synchronized的加锁过程

在synchronized加锁之前会经历一下升级过程

3.1锁升级

1.偏向锁阶段

这里的偏向锁阶段的实现和之前讲解的“懒汉模式”是有一定的联系的,即非必要不加锁,但是这里的偏向锁,并不是真正意义上的加锁;

偏向锁:即一种非必要不加锁的模式,真正意义上是不加锁的,而是进行一次轻量级的标记

这里就是当没有锁进行竞争的话就会不加锁,只是轻量化标记一下,当有锁的竞争,那么这个标记的就会很快拿到锁;

偏向锁的作用: 存在锁冲突的情况下,这中锁没有提高效率,但是当没有锁的竞争后,因为只是轻量化标记,而不加锁,那么这里的效率就会得到很大的提升;

2.轻量级锁

轻量级锁:即通过自旋的方式进行实现,反复快速的进行加锁的操作

优点:在锁的释放后,能够快速的拿到并加上锁;

缺点:非常消耗CPU的资源;

这里synchronized会根据有多少个线程在参与竞争,如果比较多,那么就会升级成重量级锁;

3.重量级锁

重量级锁:即拿不到锁的线程不会进入自旋状态,而是进入阻塞状态,释放CPU资源;

最后由内核进行随机调度,从而加上锁;

3.2锁消除

锁消除:即synchronized的一种优化策略,但是比较保守;

即编译器在编译的时候优化一下两种情况:

1.不存在锁竞争,只有一个线程,那么此时就会进行锁消除

2.加锁的代码中没有涉及到成员变量的改动,只有局部变量的改动,就不需要进行加锁

3.3锁粗化

锁粗化:即讲一个细粒度的锁,转化为一个粗粒度的锁;

粒度:即在synchronized{ },这个括号里的代码越少,即粒度越细;代码越多,即粒度越粗

所谓的粒度粗化,如下图所示:

可以发现,这里频繁的加锁解锁会造成额外的时间开销,而直接一步到位可以剩下这部分的时间开销;

📚️4.CAS的实现原理

4.1CAS的内部逻辑

所谓的CAS即compare and swap,即一种比较和交换,这是一个特殊的CPU的指令

其内部伪代码:

boolean CAS(address,expectValue,swapValue){
      if(&address==expectValue){
          &address=swapValue;
          return true;
      }
      return false
}

 注意:这里是一段伪代码,不能进行运行,只是描述逻辑的,即先进行判断寄存器的值和地址值是否相等,相等就将另一个swap寄存器的值给地址值(内存地址值)

4.2CAS实现线程安全

CAS是CPU的一种指令,操作系统又对这个指令进行了封装,我们的Java又对操作系统的API进行了封装,那么我们就可以进行使用啦;

在之前我们在实现两个线程对count实现加法操作,需要进行加锁,但是有了CAS就可以不用进行加锁了;

代码如下:

public static AtomicInteger count=new AtomicInteger();
    public static void main(String[] args) throws InterruptedException {
        Thread t1=new Thread(()->{
            for (int i = 0; i <50000 ; i++) {
                count.getAndIncrement();
            }
        });
        Thread t2=new Thread(()->{
            for (int i = 0; i <50000 ; i++) {
                count.getAndIncrement();
            }
        });
        t1.start();
        t2.start();

        t1.join();
        t2.join();
        System.out.println("最终count的值为:"+count.get());
    }

这里就是通过使用原子类工具,实现了没有加锁的仍然线程安全的代码;

注意:之前的count++是三个指令,在线程的随机调度中存在不同指令的穿插的情况,导致线程安全问题,但是getandincrement本来就是一个线程安全的指令(就是一个指令),天然就具有原子性;

4.3CAS的原子性

在实现原子类的伪代码如下图所示

即起初内存中的值为value,oldvalue是寄存器中的值,进入循环,当比较成功,那么就value的值就为value+1了;

当存在随机调度的时候:

 

那么此时就会有以下操作:

第一步:执行右边线程的操作

第二步:进行随机调度走的代码

 

注意:在次比较发现内存和寄存器的值是不一样的了,此时就会进行再次读取内存,在次进行循环比较,发现一样了,就会加1跳出循环

代价:这里的代价,就是while循环造成的自旋,CPU的消耗;

📚️5.总结

💬💬本期小编讲解了关于不同锁的基本概念,包括我们经常使用synchronized的加锁过程包含的“锁升级,锁消除,锁粗化”的一系列的操作,以及CAS的实现和我们之前线程安全的代码的举例,本篇主要是涉及到(关于锁面试题)~~~

🌅🌅🌅~~~~最后希望与诸君共勉,共同进步!!!

 


💪💪💪以上就是本期内容了, 感兴趣的话,就关注小编吧。

                             😊😊  期待你的关注~~~

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

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

相关文章

【STM32单片机_(HAL库)】4-2-1【定时器TIM】定时器输出PWM实现呼吸灯实验

1.硬件 STM32单片机最小系统LED灯模块 2.软件 pwm驱动文件添加定时器HAL驱动层文件添加GPIO常用函数定时器输出PWM配置步骤main.c程序 #include "sys.h" #include "delay.h" #include "led.h" #include "pwm.h"int main(void) {HA…

【瑞萨RA8D1 CPK开发板】串口的使用和STDOUT输出重定向

串口 本次串口的使用关于时钟导致串口的波特率不对&#xff0c;坑了我很久的时间 使能时钟 串口发现一个问题就是&#xff0c;只能使用下边的时钟配置&#xff0c;修改时钟源和分频系数都会导致串口波特率不正常&#xff0c;这种问题出现在mdkrasc的使用场景之下&#xff1b…

adaptor lora基础

https://www.zhihu.com/question/508658141/answer/3340979311 adaptor和PEFT的区别&#xff1a;前者在模型子层后加一个小型的dense&#xff1b;后者直接稀疏化模型本身&#xff1b; Loading Pre-Trained Adapters — AdapterHub documentation CVPR 2024 | SD-DiT&#xff…

Python | Leetcode Python题解之第468题验证IP地址

题目&#xff1a; 题解&#xff1a; class Solution:def validIPAddress(self, queryIP: str) -> str:if queryIP.find(".") ! -1:# IPv4last -1for i in range(4):cur (len(queryIP) if i 3 else queryIP.find(".", last 1))if cur -1:return &q…

每日OJ题_牛客_小乐乐改数字_模拟_C++_Java

目录 牛客_小乐乐改数字_模拟 题目解析 C代码 Java代码 牛客_小乐乐改数字_模拟 小乐乐改数字_牛客题霸_牛客网 (nowcoder.com) 描述&#xff1a; 小乐乐喜欢数字&#xff0c;尤其喜欢0和1。他现在得到了一个数&#xff0c;想把每位的数变成0或1。如果某一位是奇数&#…

【网络安全】CVE-2024-46990: Directus环回IP过滤器绕过实现SSRF

未经许可,不得转载。 文章目录 背景漏洞详情受影响版本解决方案背景 Directus 是一款开源 CMS,提供强大的内容管理 API,使开发人员能够轻松创建自定义应用程序,凭借其灵活的数据模型和用户友好的界面备受欢迎。然而,Directus 存在一个漏洞,允许攻击者绕过默认的环回 IP …

大数据之——VWare、Ubuntu、CentOs、Hadoop安装配置

前言&#xff1a;这里很抱歉前几期考研专题以及PyTorch这些内容都没有更新&#xff0c;并不是没有在学了&#xff0c;而是事太鸡儿多了&#xff0c;前不久刚刚打完华为开发者比赛&#xff0c;然后有紧接着高数比赛、考研复习&#xff0c;因此这些后续文章都在草稿状态中&#x…

Allegro在PCB上开槽的三种方法操作指导

Allegro如何在PCB上开槽的三种方法操作指导 当PCB有特殊设计要求的时候&#xff0c;需要在PCB上开槽&#xff0c;Allegro支持在PCB上开槽操作&#xff0c;具体操作如下 以下图为例&#xff0c;需要在这个板框中间开槽 开方形槽 选择shape add rect命令 画在Board Geometry-o…

【技术详解】SpringMVC框架全面解析:从入门到精通(SpringMVC)

文章目录 【技术详解】SpringMVC框架全面解析&#xff1a;从入门到精通(SpringMVC)SpringMVC概述1. 三层架构与MVC架构区别1.1 三层架构1.2 MVC架构1.3前后端分离开发模式 2. SpringMVC环境搭建2.1 注解启动方式2.2 xml启动方式2.3 SpringMVC PostMan工具使用 3. SpringMVC 请求…

MySQL 实验1:Windows 环境下 MySQL5.5 安装与配置

MySQL 实验1&#xff1a;Windows 环境下 MySQL5.5 安装与配置 目录 MySQL 实验1&#xff1a;Windows 环境下 MySQL5.5 安装与配置一、MySQL 软件的下载二、安装 MySQL三、配置 MySQL1、配置环境变量2、安装并启动 MySQL 服务3、设置 MySQL 字符集4、为 root 用户设置登录密码 一…

【华为欧拉】国产OpenEuler服务器系统安装以及图形界面

openEuler下载 | openEuler ISO镜像 | openEuler社区官网 下载安装iso 本次选择4G的社区版本 安装&#xff0c;复制到光盘&#xff0c;光盘引导安装。虚拟机安装&#xff0c;准备好iso文件引用&#xff0c;指定好安装源&#xff0c;安装界面和centOS基本一样。选择最小安装就…

代码随想录算法训练营第三十天|491. 非递减子序列,46. 全排列,47. 全排列 II,332. 重新安排行程,51. N 皇后,37. 解数独

491. 非递减子序列&#xff0c;46. 全排列&#xff0c;47. 全排列 II&#xff0c;332. 重新安排行程&#xff0c;51. N 皇后&#xff0c;37. 解数独 491. 非递减子序列46. 全排列47. 全排列 II332. 重新安排行程51. N 皇后37. 解数独 491. 非递减子序列 给你一个整数数组 nums…

友思特方案 | FantoVision边缘计算:嵌入式视觉系统如何实现“更快 更高 更强”?

导读 便于集成的嵌入式视觉系统一直以来面临着带宽、内存、算力三个方面的挑战。友思特 FantoVision 边缘计算设备拥有更快的处理速度和更高的带宽选择&#xff0c;其开放式架构有效突破了上述三重阻碍。 嵌入式视觉 嵌入式视觉是传统机器视觉衍生出来的子集&#xff0c;嵌入…

k8s 中存储之 PV 持久卷 与 PVC 持久卷申请

目录 1 PV 与 PVC 介绍 1.1 PersistentVolume&#xff08;持久卷&#xff0c;简称PV&#xff09; 1.2 PersistentVolumeClaim&#xff08;持久卷声明&#xff0c;简称PVC&#xff09; 1.3 使用了PV和PVC之后&#xff0c;工作可以得到进一步的细分&#xff1a; 2 持久卷实验配置…

UE5运行时动态加载场景角色动画任意搭配-相机及运镜(二)

通过《MMD模型及动作一键完美导入UE5》系列文章,我们可以把外部场景、角色、动画资产导入UE5,接下来我们将实现运行时动态加载这些资产,并任意组合搭配。 1、运行时播放相机动画 1、创建1个BlueprintActor,通过这个蓝图动态创建1个LevelSequence,并Play 2、将这个Bluep…

Verdin AM62使用CODESYS

By Toradex 胡珊逢 简介 CODESYS 是基于 IEC 61131-3 的 PLC 开发工具&#xff0c;在工业控制、交通等领域中有着广泛的应用。文章将介绍如何在 Toradex 采用 TI AM62 SoC 的 Arm 计算机模块 Verdin AM62 使用评估版本的 CODESYS。 硬件介绍 Verdin AM62使用 TI AM623/AM625…

打卡第四天 P1081 [NOIP2012 提高组] 开车旅行

今天是我打卡第四天&#xff0c;做个省选/NOI−题吧(#^.^#) 原题链接&#xff1a;[NOIP2012 提高组] 开车旅行 - 洛谷 题目描述 输入格式 输出格式 输入输出样例 输入 #1 4 2 3 1 4 3 4 1 3 2 3 3 3 4 3 输出 #1 1 1 1 2 0 0 0 0 0 输入 #2 10 4 5 6 1 …

✨机器学习笔记(七)—— 交叉验证、偏差和方差、学习曲线、数据增强、迁移学习、精确率和召回率

机器学习笔记&#xff08;七&#xff09; 1️⃣评估模型&#x1f397;️使用测试集评估模型&#x1f397;️交叉验证集&#xff08;cross validation&#xff09; 2️⃣偏差和方差&#xff08;Bias / Variance&#xff09;3️⃣学习曲线&#xff08;Learning curves&#xff09…

获取时隔半个钟的三天

摘要&#xff1a; 今天遇到需求是配送时间&#xff0c;时隔半个钟的排线&#xff01;所以需要拼接时间&#xff01;例如2024-10-08 14&#xff1a;30&#xff0c;2024-10-08 15&#xff1a;00&#xff0c;2024-10-08 15&#xff1a;30 <el-form-item label"配送时间&a…

【HarmonyOS】HMRouter使用详解(四)路由拦截

路由拦截器 可以对指定或全局路由跳转时添加拦截器&#xff0c;作用是可以实现在页面切换前做判断是否有进入当前页面的权限。这篇文章将实现登录的全局路由拦截样式。 新建拦截器类 通过继承IHMInterceptor接口实现生命周期接口的方法重写。 通过添加HMInterceptor装饰器&…