[锁]:乐观锁与悲观锁

文章目录

  • 摘要
  • 1 锁的相关概念
    • 1.1 为什么需要锁?
    • 1.2 本地锁
  • 2 乐观锁与悲观
    • 2.1 乐观锁
      • 2.1.1 乐观锁的概念
      • 2.1.2 乐观锁的解决思想
        • 2.1.2.1 数据版本号机制思想
          • 2.1.2.1.1 数据版本号机制实现——基于mybatis
            • 2.1.2.1.1.1 实体类中添加响应字段,并设定当前字段用于记录数据的版本信息
            • 2.1.2.1.1.2 使用乐观锁前必须先获取对应数据版本号
        • 2.1.2.2 CAS算法思想
    • 2.2 悲观锁
      • 2.2.1 悲观锁的概念
      • 2.2.2 悲观锁的解决思想
        • 2.2.2.1

摘要

摘要:乐观锁;悲观锁;实现方法;本地锁;分布式锁

1 锁的相关概念

1.1 为什么需要锁?

问题

  • ① 在多个线程访问共享资源时,会发生线程安全问题,例如:在根据订单号生成订单时,若用户第一次由于某种原因(网络连接不稳定)请求失败,则会再次发生请求,此时便会产生同一订单号生成多个订单,这显然是有问题的。

解决

  • ① 针对上述问题,我们有一个解决思想,给用户第一次的请求加锁,只有当前第一次请求拥有锁,请求线程在拥有锁时,方可执行,其他线程必须在拥有锁的线程执行完毕后,方可执行。

1.2 本地锁

问题

  • ① 目前的系统架构,大体分为两类:一类是单体架构,另一类是分布式架构(在分布式架构中为保障系统的高可用,我们又会搭集群),
  • ② 针对上述两类架构的特点,锁又分成两种不同的类别:一类是针对单体架构的锁,称之为本地锁,另一类是针对分布式架构的锁,称之为分布式锁。
  • ③ 针对本地锁,又有两类:一类是在高并发场景下,编程语言实现对自己多线程控制的本地锁,诸如:Java语言中synchronized、Lock本地锁(同时也是悲观锁),另一类是在数据库中实现的锁思想,诸如:乐观锁、悲观锁、共享锁、排它锁、记录锁、间隙锁、表锁等本地锁,其都可以称之为本地锁,保证业务数据的准确性。

解决

  • ① 本地锁:针对单体架构项目高并发特点,有两类解决方案:一类是语言自己实现的,例如Java语言的synchronized、Lock锁,另一类是在数据库中实现的锁思想,例如乐观锁与悲观锁,本文也着重于此两点说明。
  • ② 分布式锁:由于编程语言自己实现的锁,无法满足在分布式架构中多链路调用情况,因而出现分布式锁的思想他的解决主要有:Redisson、zookeeper、数据库(数据库性能低,使用场景少),详情请参阅另一篇文章:[分布式锁]:Redis与Redisson

2 乐观锁与悲观

通俗理解:乐观锁,对一件事持乐观态度,认为大概率不会发生;悲观锁,对一件事持悲观态度,认为大概率会发生。

2.1 乐观锁

2.1.1 乐观锁的概念

概念:认为大概率不会发生线程安全问题。

2.1.2 乐观锁的解决思想

2.1.2.1 数据版本号机制思想

① 首先,给数据库添加一个字段version(int)的标记字段,
② 随后,当多个线程同时访问数据库时,都会获得version的值,
③ 然后,在提交更新时若刚才读取到的version为当前数据库中中version值时才更新,伴随着更新过后version的值也会发生变化,
④ 最后,当其他线程需要提交更新时,获取到的version值和当前数据库version值不一样,提交更新失败,从而实现对线程安全的控制。

2.1.2.1.1 数据版本号机制实现——基于mybatis

引入业务场景:假设数据库中账户有一version字段(值为1),且当前账户余额balance字段(值为100)

  • ① 操作员A此时将其读出(此时version=1),并从账户余额中扣除50(100-50),
  • ② 操作员A操作的同时,操作员B也读出此账户信息(此时version=1),并从账户余额扣除20(100-20),
  • ③ 操作员A先完成了修改工作,并且,将数据版本号(version=1)和账户扣除后余额(balance=50),提交至数据库更新,此时由于提交数据版本=当前数据库记录版本,数据被成功更新,数据版本更新为2(version=2),
  • ④ 操作员B完成操作后,也将读出到的数据版本(version=1)和账户扣除后余额(balance=80),提交至数据库请求更新,此时数据库数据版本已经被更新(version=2),不满足数据版本号相同时,才能更新数据的策略,因此操作员B请求被驳回。从而保证数据的的准确。
2.1.2.1.1.1 实体类中添加响应字段,并设定当前字段用于记录数据的版本信息
@Configuration
public class MpConfig {
    @Bean
    public MybatisPlusInterceptor mpInterceptor() {
        //1.定义Mp拦截器
        MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();

        //2.添加乐观锁拦截器
        mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        
        return mpInterceptor;
    }
}

2.1.2.1.1.2 使用乐观锁前必须先获取对应数据版本号

注意:由于在使用乐观锁时需要跟数据库频繁进行交互,因而在高并发场景下,建议使用分布式锁和悲观锁(是的,乐观锁也可以作为分布式锁来使用)。

@Test
public void testUpdate() {
    /*User user = new User();
    user.setId(3L);
    user.setName("Jock666");
    user.setVersion(1);
    userDao.updateById(user);*/
    
    //1.先通过要修改的数据id将当前数据查询出来
    //User user = userDao.selectById(3L);
    //2.将要修改的属性逐一设置进去
    //user.setName("Jock888");
    //userDao.updateById(user);
    
    //1.先通过要修改的数据id将当前数据查询出来
    User user = userDao.selectById(3L);     //version=3
    User user2 = userDao.selectById(3L);    //version=3
    user2.setName("Jock aaa");
    userDao.updateById(user2);              //version=>4
    user.setName("Jock bbb");
    userDao.updateById(user);               //verion=3?条件还成立吗?
}

2.1.2.2 CAS算法思想

  • 实现思想:CAS算法基于ccompare-and-swap(比较和交互)操作,类似于Junit的断言机制,其通过比较当前值和期望值的方式,实现乐观锁的并发控制机制。
  • 使用说明:在使用时,先读取数据的原值,根据规则计算出新的期望值,随后,使用CAS操作把期望值写入数据的存储位置,若操作成功,说明没有发生冲突,更新操作可以提交,否则,操作失败,需要重新读取数据并重复以上操作。
  • 问题:一方面是数据库性能问题,另一当面是ABA问题。
  • ABA问题:当前有ABC三个线程,初始数据版本号为V1,线程AB分别查询到该数据的版本号是V1,线程A先更新数据,把版本改为A2,然后线程C也执行一次操作把版本号从V1更改成V3随后又改回V1,此时当线程B更新时发现数据版本匹配,更新操作成功,但实际数据已经被C修改,因此为避免此问题又需借助时间戳、版本号机制来解决。

2.2 悲观锁

2.2.1 悲观锁的概念

悲观锁:认为大概率会发生线程安全问题。

2.2.2 悲观锁的解决思想

悲观锁的核心思想:在操作共享数据之前对其进行加锁,保证同一时刻只有一个线程可以访问

2.2.2.1

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

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

相关文章

linuxOPS基础_linux软件包安装

软件包概述 上图是windows下的软件包 Linux下也有很多可以安装的软件,而这些软件的安装包可细分为两种,分别是源码包和二进制包。 Linux下软件的安装方式 ① RPM软件包安装 > 软件名称.rpm ② YUM包管理工具 > yum install 软件名称 -y ③ 源码…

基于QGIS的长株潭城市群边界范围融合实战

背景 在面向区域的研究过程中,比如一些研究区域,如果是具体的行政区划,比如具体的某省或者某市或者县,可以直接从国家官方的地理数据中直接下载就可以。但如果并没有直接的空间数据那怎么办呢?比如之前遇到的一个场景&…

【郭东白架构课 模块二:创造价值】31 |节点六: 如何组织阶段性的价值交付?

你好,我是郭东白。上节课我们讲了为什么要做阶段性的价值交付,以及进入阶段性价值交付环节的准备工作。有了这些学习基础,这节课我们就可以进行阶段性价值交付了。 在交付的过程中,主要有三部分工作:目标分解、定义交…

数据结构——堆(C语言实现)

文章目录 什么是堆堆的实现堆的结构定义堆的初始化接口堆的销毁接口堆的插入数据接口向上调整建堆接口判断堆是否为空堆的删除数据接口向下调整建堆接口获取堆顶数据获取堆的有效数据个数完整实现代码小结 堆排序堆排序的实现 关于建堆和堆排序时间复杂度的分析向下调整建堆向上…

day52|动态规划13-子序列问题

子序列系列问题 300.最长递增子序列 什么是递增子序列: 元素之间可以不连续,但是需要保证他们所在位置是元素在数组中的原始位置。 dp数组dp[i]表示以nums[i]为结尾的最长递增子序列的长度。递归函数:dp[i] max(dp[j]1,dp[j])初始化条件&…

算法刷题-链表-移除链表元素

链表操作中,可以使用原链表来直接进行删除操作,也可以设置一个虚拟头结点再进行删除操作,接下来看一看哪种方式更方便。 203.移除链表元素 力扣题目链接 题意:删除链表中等于给定值 val 的所有节点。 示例 1: 输入&…

Linux下信号量使用总结

目录 1.Linux下信号量简介 2.POSIX信号量 2.1 无名信号量 2.2 有名信号量 3.System V信号量 1.Linux下信号量简介 信号量是解决进程之间的同步与互斥的IPC机制,互斥与同步关系存在的症结在于临界资源。 临界资源是在同一个时刻只容许有限个(一般只有…

【数据结构与算法】03 队列(顺序队列--循环队列--优先级队列--链队列)

一、概念1.1 队列的基本概念1.2 队列的顺序存储结构1.21 顺序队列(静态队列)1.22 循环队列1.23 优先级队列 1.3 队列的链式存储结构 二、C语言实现2.1 顺序存储2.11 顺序队列2.12 循环队列2.13 优先级队列 2.2 链式存储 一、概念 1.1 队列的基本概念 队…

Linux内核中断和Linux内核定时器

目录 Linux内核中断 Linux内核定时器 Linux内核中断 int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev) 功能:注册中断 参数: irq : 软中断号 gpio的软中断号 软中断号 gpio_to_i…

【PCB专题】案例:绕等长怎么直接以颜色区分看出是否绕好

PCB上对于时序的处理,在板卡上实际我们是通过绕等长的手段。做为一个合格的Layout工程师,等长的处理是不可或缺的技能。 一般来说,在绕等长的时候我们可以使用Delay Tune命令来改变走线的长度,然后通过规则管理器中分析看看哪根线长哪根线短。 但是在实际工作中,很可能绕着…

Android应用程序进程的启动过程

Android应用程序进程的启动过程 导语 到这篇文章为止,我们已经简要地了解过了Android系统的启动流程了,其中比较重要的内容有Zygote进程的启动和SystemService以及Launcher的启动,接下来我们将要学习的是Android应用程序的启动过程&#xff…

华为OD机试真题 JavaScript 实现【最多几个直角三角形】【2023Q1 100分】

一、题目描述 有 N 条线段&#xff0c;长度分别为 a[1]-a[n]。 现要求你计算这 N 条线段最多可以组合成几个直角三角形&#xff0c;每条线段只能使用一次&#xff0c;每个三角形包含三条线段。 二、输入描述 第一行输入一个正整数 T (1< T< 100) &#xff0c;表示有…

2023蓝桥杯大学A组C++决赛游记+个人题解

Day0 发烧了一晚上没睡着&#xff0c;感觉鼻子被打火机烧烤一样难受&#xff0c;心情烦躁 早上6点起来吃了个早饭&#xff0c;思考能力完全丧失了&#xff0c;开始看此花亭奇谭 看了六集&#xff0c;准备复习数据结构考试&#xff0c;然后秒睡 一睁眼就是下午2点了 挂了个…

springboot项目外卖管理 day05-新增与删除套餐

文章目录 一、新增菜品1.1、需求分析1.2、数据模型setmealsetmeal_dish 1.3、代码开发-梳理交互过程1.3.1、下拉框展示1.3.2、菜品窗口展示1.3.3、新增套餐 2、套餐分页查询 一、新增菜品 1.1、需求分析 套餐就是菜品的集合。 后台系统中可以管理套餐信息&#xff0c;通过新…

一文打通:从字节码指令的角度解读前置后置自增自减(加加++减减--)

文章目录 1.前置了解的知识1.1 栈这种数据结构1.2 局部变量表和操作数栈1.3 三个字节码指令 2.单独使用后置与前置2.1 后置字节码指令2.2 前置字节码指令2.3 总结 3.需要返回值的情况下使用后置与前置3.1 后置字节码指令3.2 前置字节码指令3.3 总结3.4 练习&#x1f340; 练习一…

了解ASEMI代理英飞凌TLE6208-6G其功能和应用的综合指南

编辑-Z TLE6208-6G是一款高度集成、通用且高效的汽车半桥驱动器&#xff0c;由英飞凌设计。这种功能强大的设备专门设计用于满足汽车应用的苛刻要求&#xff0c;如控制直流电机、螺线管和电阻负载。在本文中&#xff0c;我们将深入研究TLE6208-6G的功能、优点和应用&#xff0…

实现表白墙

我们已经学习了Http以及Servlet类的相关知识 今天我们来实操一下,实现一个简单的既有前端又有后端的网站–表白墙 之前在学习前端的时候已经写过了表白墙的前端代码,存在两个问题 1.页面重启,数据丢失 2.数据只是在本地的,别人看不见 那么这样的问题我们要咋样解决呢? 引入…

(七)CSharp-CSharp图解教程版-事件

一、发布者和订阅者 发布者/订阅者模式&#xff08;publish/subscriber pattern&#xff09;&#xff1a; 很多程序都有一个共同的需求&#xff0c;即当一个特定的程序事件发生时&#xff0c;程序的其他部分可以得到该事件已经发生的通知。 发布者&#xff1a; 发布者类定义…

Excel函数VLOOKUP常用方法

一、基础用法 1、精确匹配 公式&#xff1a;VLOOKUP(待匹配值&#xff0c;查找范围&#xff0c;范围列数&#xff0c;查找方式) 定义好要输出表的表头和第一列&#xff0c;第一列即为要查找和匹配的父内容&#xff0c;在第二列输入公式&#xff0c;被查找表中一定也要将待查…

基于SPAD / SiPM技术的激光雷达方案

激光雷达(LiDAR)是一种测距技术&#xff0c;近年来越来越多地用于汽车先进驾驶辅助系统(ADAS)、手势识别和3D映射等应用。尤其在汽车领域&#xff0c;随着传感器融合的趋势&#xff0c;LiDAR结合成像、超声波、毫米波雷达&#xff0c;互为补足&#xff0c;为汽车提供全方位感知…
最新文章