乐观锁与悲观锁

news2024/11/6 3:04:08

概述

悲观锁总会假设最坏的情况,乐观锁总会假设最好的情况。悲观锁和乐观锁最终都是为了保证线程的安全,避免在并发场景下的资源竞争问题,但是,相对于乐观锁,悲观锁对性能的影响更大!

悲观锁

共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其他线程。
高并发的场景下,激烈的锁竞争会造成线程阻塞,大量阻塞线程会导致系统的上下文切换,增加系统的性能开销。并且,悲观锁还可能会存在死锁问题,影响代码的正常运行。
线程切换意味着需要保存当前线程的上下文,留待线程下次占用 CPU 的时候恢复现场。并加载下一个将要占用 CPU 的线程上下文。这就是所谓的 上下文切换。
sycchronized和ReenteantLock等独占锁都是悲观锁思想的实现。

乐观锁

共享资源每次被访问的时候不会出现问题,线程可以不停地执行,无需加锁也无需等待,只是在提交修改的时候去验证对应的资源(也就是数据)是否被其它线程修改了(具体方法可以使用版本号机制或 CAS 算法)。
比如atomic 包下的原子类就是使用CAS 实现的
在这里插入图片描述
LongAdder 在高并发场景下会比 AtomicInteger 和 AtomicLong 的性能更好但是会消耗更多的空间

比较

高并发的场景下,乐观锁相比悲观锁来说,不存在锁竞争造成线程阻塞,也不会有死锁的问题,在性能上往往会更胜一筹。但是,如果冲突频繁发生(写占比非常多的情况),会频繁失败和重试(悲观锁的开销是固定的),这样同样会非常影响性能,导致 CPU 飙升。
不过,大量失败重试的问题也是可以解决的,像我们前面提到的 LongAdder以空间换时间的方式就解决了这个问题。

悲观锁

悲观锁通常多用于写比较多的情况下(多写场景,竞争激烈),这样可以避免频繁失败和重试影响性能,悲观锁的开销是固定的。不过,如果乐观锁解决了频繁失败和重试这个问题的话(比如LongAdder),也是可以考虑使用乐观锁的,要视实际情况而定。

乐观锁

乐观锁通常多于写比较少的情况下(多读场景,竞争较少),这样可以避免频繁加锁影响性能。不过,乐观锁主要针对的对象是单个共享变量(参考java.util.concurrent.atomic包下面的原子变量类)。

如何实现乐观锁

版本号

一般是在数据表中加上一个数据版本号 version 字段,表示数据被修改的次数。当数据被修改时,version 值会加一。当线程 A 要更新数据值时,在读取数据的同时也会读取 version 值,在提交更新时,若刚才读取到的 version 值为当前数据库中的 version 值相等时才更新,否则重试更新操作,直到更新成功。

CAS

CAS 的全称是 Compare And Swap(比较与交换) ,用于实现乐观锁,被广泛应用于各大框架中。CAS 的思想很简单,就是用一个预期值和要更新的变量值进行比较,两值相等才会进行更新。
CAS 是一个原子操作,底层依赖于一条 CPU 的原子指令。原子操作 即最小不可拆分的操作,也就是说操作一旦开始,就不能被打断,直到操作完成。
CAS 涉及到三个操作数:

  1. V:要更新的变量值(Var)
  2. E:预期值(Expected)
  3. N:拟写入的新值(New)
    当且仅当 V 的值等于 E 时,CAS 通过原子方式用新值 N 来更新 V 的值。如果不等,说明已经有其它线程更新了 V,则当前线程放弃更新。

sun.misc包下的Unsafe类提供了compareAndSwapObject、compareAndSwapInt、compareAndSwapLong方法来实现的对Object、int、long类型的 CAS 操作

乐观锁存在的问题

ABA 问题

如果一个变量 V 初次读取的时候是 A 值,并且在准备赋值的时候检查到它仍然是 A 值,那我们就能说明它的值没有被其他线程修改过了吗?很明显是不能的,因为在这段时间它的值可能被改为其他值,然后又改回 A,那 CAS 操作就会误认为它从来没有被修改过。这个问题被称为 CAS 操作的 "ABA"问题。

ABA 问题的解决思路是在变量前面追加上版本号或者时间戳。JDK 1.5 以后的 AtomicStampedReference 类就是用来解决 ABA 问题的,其中的 compareAndSet() 方法就是首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。

public boolean compareAndSet(V   expectedReference,
                             V   newReference,
                             int expectedStamp,
                             int newStamp) {
    Pair<V> current = pair;
    return
        expectedReference == current.reference &&
        expectedStamp == current.stamp &&
        ((newReference == current.reference &&
          newStamp == current.stamp) ||
         casPair(current, Pair.of(newReference, newStamp)));
}

循环开销大

CAS 经常会用到自旋操作来进行重试,也就是不成功就一直循环执行直到成功。如果长时间不成功,会给 CPU 带来非常大的执行开销。
如果 JVM 能支持处理器提供的 pause 指令那么效率会有一定的提升,pause 指令有两个作用:

  1. 可以延迟流水线执行指令,使 CPU 不会消耗过多的执行资源,延迟的时间取决于具体实现的版本,在一些处理器上延迟时间是零。
  2. 可以避免在退出循环的时候因内存顺序冲而引起 CPU 流水线被清空,从而提高 CPU 的执行效率。
只能保证一个共享变量的原子操作

CAS 只对单个共享变量有效,当操作涉及跨多个共享变量时 CAS 无效。但是从 JDK 1.5 开始,提供了AtomicReference类来保证引用对象之间的原子性,你可以把多个变量放在一个对象里来进行 CAS 操作.所以我们可以使用锁或者利用AtomicReference类把多个共享变量合并成一个共享变量来操作。

作者声明

如有问题,欢迎指正!

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

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

相关文章

操作系统权限提升(二十六)之数据库提权-MySQL UDF提权

MySQL UDF提权 MySQL介绍 MySQL是最流行的开放源码SQL数据库管理系统&#xff0c;相对于Oracle&#xff0c;DB2等大型数据库系统&#xff0c;MySQL由于其开源性、易用性、稳定性等特点&#xff0c;受到个人使用者、中小型企业甚至一些大型企业的广泛欢迎&#xff0c;MySQL具有…

点大商城V2_2.5.0 全开源独立版 商家自营+多商户入驻 百度+支付宝+QQ+头条+小程序端+unipp开源前端

点大商城V2是一款采用全新界面设计支持多端覆盖的小程序应用&#xff0c;支持H5、微信公众号、微信小程序、头条小程序、支付宝小程序、百度小程序&#xff0c;本程序是点大商城V2独立版&#xff0c;包含全部插件&#xff0c;代码全开源&#xff0c;并且有VUE全端代码。分销&am…

log4j2原理分析及漏洞复现CVE-2021-44228

文章目录 log4j2原理分析及漏洞复现0x01 log4j2简介Log4j2 特点Log4j2组件的应用 0x02 CVE-2021-44228漏洞简介&#xff1a;漏洞适用版本漏洞原理lookup功能jndi解析器jndi是什么ldap服务RMI 0x03攻击过程0x04漏洞复现漏洞环境1.访问靶机2.dns回显验证3.将bash反弹shell命令编码…

职业观察|02:铁路维修师

高铁及地铁的发展&#xff0c;新生了许多之前没有的职位和专业。除了空乘/铁乘、安检人员等&#xff0c;大家可能相对熟悉。背后的维系工作人员其实也是一群更庞大的从业人员。本次主要介绍“铁路机务”。以下由一位铁路机务小哥讲述。 首先简单介绍一下铁路系统&#xff08;包…

准备我们心爱的IDEA写Jsp

JSP学习 一、准备我们心爱的IDEA new一个项目&#xff1a;New Project --> Next -->Next -->Finsh 二、配置好服务器Tomcat-9.0.30 1.> 在WEB-INF下创建一个Lib包 将jsp-api.jar复制进去&#xff0c;并使其生效 未生效前&#xff1a; 生效过程&#xff1a; 2.>…

VLAN相关知识点

文章目录 前言VLANVLAN数据帧格式QinQ报文封装格式总结 前言 本博客仅做学习笔记&#xff0c;如有侵权&#xff0c;联系后即刻更改 科普&#xff1a; 参考网址 VLAN VLAN&#xff08;Virtual Local Area Network&#xff09;即虚拟局域网 是将一个物理的LAN在逻辑上划分成多…

Filebeat+Kafka+ELK搭建

---------------- FilebeatKafkaELK ---------------- 1.部署 ZookeeperKafka 集群 &#xff08;前面已经配过 20.0.0.101、20.0.0.102、20.0.0.103&#xff09; https://blog.csdn.net/m0_56509725/article/details/132908696?spm1001.2014.3001.55011.1 配置ELK 在&#xf…

阿里云负载均衡配置只能域名访问

1.选择虚拟服务器组》创建虚拟服务器组 2.点击创建虚拟服务器组》输入虚拟服务器组名称&#xff0c;注意&#xff1a;不要添加服务器&#xff0c;直接点击创建 3.在点击创建虚拟服务器组》输入虚拟服务器组名称》添加服务器&#xff08;后端服务器&#xff09;》创建 1.添加监…

WhatsOnChain中的sCrypt合约验证插件

我们很高兴地宣布在 WhatsOnChain 上集成了 sCrypt 智能合约验证插件。该插件允许任何人为已部署的智能合约提交和验证 sCrypt 代码。 智能合约验证 在与智能合约交互之前&#xff0c;用户需要确保智能合约按照其声称的方式行事。理论上&#xff0c;每个人都可以查看合约并验…

脸鉴AI开放平台:轻松上手的人工智能算法

序言 一、提升开发效率工具 1.1封装view窗口 1.2封装常用功能接口 1.3提供基础接口代码块 二、使用介绍 2.1 注册&登录 2.2 新建应用 2.3 下载应用 2.4 安装包介绍 2.5 demo项目 2.6 配置demo 2.7 运行demo 三、使用结果 3.1 摄像头采集人脸添加模板 3.2 实时画面1:N人脸检…

出现 conda虚拟环境默认放在C盘 解决方法

目录 1. 问题所示2. 原理分析3. 解决方法3.1 方法一3.2 方法二1. 问题所示 通过conda配置虚拟环境的时候,由于安装在D盘下,但是配置的环境默认都给我放C盘 通过如下命令:conda env list,最后查看该环境的确在C盘下 2. 原理分析 究其根本原因,这是因为默认路径没有足够的…

c#用Gnuplot画图源码

直接调用这个类即可&#xff0c;需要下载个GnuPlot安装下。 // Author: Leonardo Tazziniusing System; using System.Diagnostics; using System.Drawing; using System.IO; using System.Windows.Forms;/// <summary> /// Tested with Gnuplot 5.2 /// </summary&g…

【Unity实战】从零手戳一个库存背包系统

文章目录 前言素材开始一、绘制背包UI二、背包开启关闭三、初始化背包网格四、 添加物品五、 拖拽交换功能物品六、 物品拆分七、 物品堆叠八、 拖拽还原九、 引入字典存储数据十、 拾取物品十一、 丢弃物品 最终效果源码完结 前言 库存背包系统是大多数游戏的关键部分&#x…

富金通管理U盾不轻松,用了USB Server如沐清风

富金通网络科技服务有限公司是一家专注于金融科技服务的公司&#xff0c;因为拥有多个银行账户&#xff0c;也就有了U盾数量过多、管理极为不便的问题&#xff0c;具体表现为易丢失、易损坏、操作繁琐、需要插拔、不便携带、威胁金融安全等。 近期&#xff0c;朝天椒USB Serve…

【TCP】确认应答 与 超时重传

确认应答 与 超时重传 一. 确认应答机制二. 超时重传机制 一. 确认应答机制 确认应答: 保障可靠传输的核心机制。 可靠传输: 不是指传输过去的数据不出错, 也不是指数据一定能传输过去&#xff0c;而是指发送方能够知道接收方是否接收到了数据。确认应答的关键就是接收方收到数…

java:asm实现ResultSet结果映射到实体类

java&#xff1a;asm实现ResultSet结果映射到实体类 1 前言 Spring-core包中提供了许多方便的工具类&#xff0c;其中org.springframework.cglib.beans下的BeanCopier工具类&#xff0c;主要用于bean之间的属性拷贝&#xff0c;性能上优于Spring-beans包下的org.springframew…

面试官:你了解Axios的原理吗?有看过它的源码吗?

&#x1f3ac; 岸边的风&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 一、axios的使用 二、实现一个简易版axios 三、源码分析 小结 一、axios的使用 关于axios的基本使用&#xff0…

暨南大学旅游管理《乡村振兴战略下传统村落文化旅游设计》校友许少辉—2023学生开学季辉少许

暨南大学旅游管理《乡村振兴战略下传统村落文化旅游设计》校友许少辉——2023学生开学季辉少许

软文发布是推动企业发展的无形动力 | 媒介启航

同样是销售产品&#xff0c;为什么以故事的形式呈现要比直接讲产品功效更易让消费者认同和销售呢&#xff1f;这就是软文的魅力&#xff0c;它极好的运用了人作为情感动物的喜好。因此&#xff0c;各大小企业纷纷做软文&#xff0c;比如溯源啊、初心啊、情怀啊、创业经历啊等等…

Java集成微信支付实现企业付款到零钱和商家转账到零钱的功能

Java集成微信支付实现企业付款到零钱和商家转账到零钱的功能 文章目录 [toc] 1.企业付款到零钱和商家转账到零钱的区别1.1 申请要求不同1.2 API接口不同1.3 用户收款限制1.4 商户付款额度1.5 派发方式不同1.6 打款方式不同 2.集成实现2.1 v2版本集成2.2 依赖2.3 配置2.3.1 naco…