【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的实现和我们之前线程安全的代码的举例,本篇主要是涉及到(关于锁面试题)~~~
🌅🌅🌅~~~~最后希望与诸君共勉,共同进步!!!
💪💪💪以上就是本期内容了, 感兴趣的话,就关注小编吧。
😊😊 期待你的关注~~~
相关文章:

【JavaEE初阶】深入理解不同锁的意义,synchronized的加锁过程理解以及CAS的原子性实现(面试经典题);
前言 🌟🌟本期讲解关于锁的相关知识了解,这里涉及到高频面试题哦~~~ 🌈上期博客在这里:【JavaEE初阶】深入理解线程池的概念以及Java标准库提供的方法参数分析-CSDN博客 🌈感兴趣的小伙伴看一看小编主页&am…...

详解Redis分布式锁在SpringBoot的@Async方法中没锁住的坑
背景 Redis分布式锁很有用处,在秒杀、抢购、订单、限流特别是一些用到异步分布式并行处理任务时频繁的用到,可以说它是一个BS架构的应用中最高频使用的技术之一。 但是我们经常会碰到这样的一个问题,那就是我们都按照标准做了但有时运行着、…...

怎么做接口自动化测试
在分层测试的“金字塔”模型中,接口测试属于第二层服务集成测试范畴。相比UI层(主要是WEB或APP)自动化测试而言,接口自动化测试收益更大,且容易实现,维护成本低,有着更高的投入产出比࿰…...

网络编程(18)——使用asio协程实现并发服务器
十八、day18 到目前为止,我们以及学习了单线程同步/异步服务器、多线程IOServicePool和多线程IOThreadPool模型,今天学习如何通过asio协程实现并发服务器。 并发服务器有以下几种好处: 协程比线程更轻量,创建和销毁协程的开销较…...

Koa2项目实战2(路由管理、项目结构优化)
添加路由(处理不同的URL请求) 路由:根据不同的URL,调用对应的处理函数。 每一个接口服务,最核心的功能是:根据不同的URL请求,返回不同的数据。也就是调用不同的接口返回不同的数据。 在 Node…...

决战Linux操作系统
前言: 你是否也曾经为Linux所困扰过,在网上找的资料零零散散,是否学完Linux后还是懵懵懂懂,别怕,这篇博客是博主精心为你准备的,现在,就让我们一起来走进Linux的世界,决战Linux&…...

OceanBase 3.2.2 数据库问题处理记录
只记录OceanBase 数据库与OCP的异常处理,其它组件暂时不写录。 一、问题1: 说明:OMS 出现异常,无法访问(OB无法访问) OB数据库架构:1:1:1 原因:某一台OBserver因为内存问题,被服务器直接kill掉…...

HCIP--以太网交换安全(二)端口安全
端口安全 一、端口安全概述 1.1、端口安全概述:端口安全是一种网络设备防护措施,通过将接口学习的MAC地址设为安全地址防止非法用户通信。 1.2、端口安全原理: 类型 定义 特点 安全动态MAC地址 使能端口而未是能Stichy MAC功能是转换的…...

在 Windows 11 安卓子系统中安装 APK 的操作指南
这个软件好像不可以在纯android系统中使用(不知道是缺了什么),其他对于android的虚拟机要不缺少必要功能组件,要不性能过于低下。本方法致力于在带有谷歌框架WSA中运行该APK 在 Windows 11 安卓子系统中安装 APK 的操作指南 本指…...

[C语言] 函数详解:库函数与自定义函数
文章目录 函数的概念库函数和自定义函数库函数使用库函数示例常用库函数及头文件 自定义函数自定义函数的基本结构示例:实现两个数的求和函数自定义函数的好处 函数的返回值有返回值的函数无返回值的函数 函数的声明与调用声明函数在另一个文件中调用函数示例&#…...

0x11 科迈 RAS系统 Cookie验证越权漏洞
参考: 科迈 RAS系统 Cookie验证越权漏洞 | PeiQi文库 (wgpsec.org)免责声明 欢迎访问我的博客。以下内容仅供教育和信息用途: 合法性:我不支持或鼓励非法活动。请确保遵守法律法规。信息准确性:尽管我尽力提供准确的信息,但不保证其完全准确或适用。使用前请自行验证。风…...

MoonBit 双周报 Vol.57:AI助手功能增强、表达式优先级调整、JS 交互优化、标准库与实验库API多项更新!
2024-10-08 IDE更新 AI Codelens支持 /generate 和 /fix 命令 /generate 命令能够提供一个通用的用以生成代码的聊天界面。 /fix 命令能够读取当前函数的错误信息给出修复建议。 MoonBit更新 调整中缀表达式和if、match、loop、while、for、try表达式的优先级, 后者这些控制…...

element ui input textarea控制显示高度
样式代码 .testPage { position: absolute; left: 0; top: 0; right: 0; bottom: 0; display: flex; height: 100%; /* 控制输入框高度 */ .el-textarea { height: 90%; ::v-deep .el-textarea__inner { height: 90%; } } }...

Chromium 中chrome.downloads扩展接口c++
一、前端chrome.downloads 使用 chrome.downloads API 以编程方式启动、监控、操作和搜索下载内容。 权限 downloads 您必须在扩展程序清单中声明 "downloads" 权限,才能使用此 API。 {"name": "My extension",..."permiss…...

微信小程序常见问题
一、编译报错 [ app.json 文件内容错误] app.json: 在项目根目录未找到 app.json 解决办法: 微信开发者工具中打开设置->安全设置->打开服务端口用HBuilder X打开小程序文件夹,点击“运行到小程序模拟器”,生成配置文件,…...

进程的理解
进程的理解 目录: 什么是进程主要特征主要组成部分进程状态进程优先级 1.什么是进程 概念: 在操作系统中,**进程(Process)**是一个正在执行的程序实例。可以将进程理解为一个动态的实体,它不仅包括静态…...

LeetCode494:目标和
题目链接:494. 目标和 - 力扣(LeetCode) 代码如下 class Solution { public:int findTargetSumWays(vector<int>& nums, int target) {int sum 0;for(int i 0; i < nums.size(); i){sum nums[i];}if(abs(target) > sum)…...

vue3中自定义校验函数密码不生效问题
vue3中自定义校验函数密码不生效问题 由于在自定义的校验规则中只校验了有数据的情况,以至于在没输入时,校验不生效 (1)用户不输入校验不生效 const validateSurePassword (rule, value, callback) > {if (value ! ) {if (…...

RabbitMQ(死信队列)
一、本文抒写背景 前面我也在延迟队列篇章提到过死信队列,也提到过一些应用场景! 今天呢,这篇文章,主要就是实战一个业务场景的小Demo流程,哈哈,那就是延迟关闭订单。 二、开始啦!letgo! 首…...

HTTP代理的优点和局限性
在这个信息爆炸的时代,网络已成为我们获取知识、交流思想、开展商务的重要平台。但随之而来的隐私泄露、网络安全威胁、以及无处不在的网络监控,却让我们的每一次在线活动都充满了风险。 在这样的背景下,HTTP代理技术应运而生,它不…...

大厂面试真题-如果通过JVM自带的工具排查和解决线上CPU100%的问题
通过JVM自带的工具去定位和解决线上CPU 100%的问题,可以遵循以下步骤: 一、使用top和jps定位Java进程 使用top命令: 在Linux服务器上执行top命令,查看所有进程的CPU使用情况。找到CPU使用率最高的进程,并记录其PID&a…...

kubernetes中微服务部署
微服务 问:用控制器来完成集群的工作负载,那么应用如何暴漏出去? 答:需要通过微服务暴漏出去后才能被访问 Service 是一组提供相同服务的Pod对外开放的接口借助Service,应用可以实现服务发现和负载均衡Service 默认只…...

基于 Java 的天气预报系统设计与实现
随着互联网的飞速发展,天气预报系统变得越来越重要。它可以帮助用户了解未来几天的天气情况,便于出行、活动安排。本文将介绍如何使用 Java 构建一个简单的天气预报系统,涉及系统架构设计、核心功能开发以及完整的代码实现。 1. 系统架构设计…...

思迅商云8前台打开提示上传日志信息失败
请按照以下步骤核实处理: 1、重启sql服务后测试。 2、请先备份前台安装目录,之后删除安装目录下的log文件和localdate下的log文件,之后重新打开软件,若依旧不行则说明前台文件有损坏,需要重新安装客户端,…...

webstorm的缩进设置(过度缩进解释)
在编写前端代码时 缩进规范一般被认为是2个空格 而非默认的4个空格 当我们通过webstorm去编写前端代码时 我们可以通过setting->Code Style->html/css/js指定的界面中去设置tab/indent/continuation indent 具体的话 我们将html/css/js操作界面中的tab/indent设置为2个空…...

与ZoomEye功能类似的搜索引擎还有哪些?(渗透课作业)
与ZoomEye功能类似的搜索引擎有: Shodan:被誉为“物联网的搜索引擎”,专注于扫描和索引连接到互联网的各种设备,如智能家居设备、工业控制系统、摄像头、数据库等。它提供全球互联网设备的可视化视图,帮助用户了解网络…...

Java 计数排序
计数排序(Counting Sort)是一种非比较型排序算法,适用于一定范围内的整数排序。它的基本思想是通过计数输入元素中每个值出现的次数,然后计算每个值的起始位置,最终将元素放到正确的位置上。计数排序的时间复杂度为 O(…...

error: RPC failed; curl 16 Error in the HTTP2 framing layer
yschai@LAPTOP-F2L146JK:~$ git clone https://github.com/Chyusen/yschai.git Cloning into ‘yschai’… error: RPC failed; curl 16 Error in the HTTP2 framing layer fatal: expected flush after ref listing 使用Ubuntu在git clone github上的项目的时候,遇到以上报错…...

Python脚本分类和代码举例
Python是一种强大且灵活的编程语言,被广泛应用于数据分析、Web开发、自动化、人工智能等领域。在不同的应用场景下,Python脚本可以被分类为多种类型。本文将深入分析Python脚本的分类,同时提供相关代码示例,帮助读者理解和应用这些…...

【Redis十二】Redis的典型应用(缓存和分布式锁)
目录 Redis作为缓存 1.什么是缓存? 2.缓存的更新策略 3.缓存预热,缓存穿透,缓存雪崩和缓存击穿 Redis作为分布式锁 1.什么是分布式锁? 2.分布式锁的实现过程 Redis是目前后端开发中非常热门的组件之一,本篇文章…...