Java面试必考问题:什么是乐观锁与悲观锁
wptr33 2024-12-22 21:12 32 浏览
我们经常会用锁机制来处理多线程的并发,本文就来讨论下悲观锁和乐观锁这两个非常常用的概念。
悲观锁
悲观锁总是假设最坏的情况,每次去拿数据的时候都认为有人会修改,所以每次在拿数据的时候都会上锁,这样其他线程想拿这个数据就得等它解锁。共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程。
传统的关系型数据库里边就用到了很多悲观锁机制,比如行锁、表锁等,都是在操作之前先上锁。Java中 synchronized 和 ReentrantLock 等独占锁就是基于悲观锁机制。
乐观锁
乐观锁总是假设最好的情况,每次去拿数据的时候都认为不会有人修改,所以不会上锁,但是在更新的时候会判断一下在此期间有没有线程更新过这个数据,可以使用版本号机制和CAS算法实现。
乐观锁适用于多读的应用类型,这样可以提高吞吐量。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的典型实现方式Compare and Swap。
乐观锁适用于写比较少的情况,即冲突很少发生的情况,这样就省去了锁的开销,加大了系统的整个吞吐量。但如果是经常产生冲突的情况,乐观锁会导致上层应用会不断进行重试,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。
乐观锁和悲观锁是一种思想,不是一项具体的技术。这两种机制不仅仅被用于Java虚拟机内部,在数据库、互联网应用中也用得非常多。
MySQL数据库自带的锁机制可以很好地解决单节点的数据访问并发问题,但是在大规模并发的场景中,由于读写性能问题是不推荐使用 MySQL的。
高并发场景下的应用
秒杀和抢购是电商系统中典型的高并发场景。这类场景中有一个非常严重的问题,就是“超发”。假设某个抢购场景中库存中仅剩最后一个商品,此时系统发来2个并发请求,这2个请求读取到的商品余量都是1个,2个请求都抢购成功,最终导致超发。
悲观锁思路
对于上述多写场景,我们可以采用悲观锁的思路,也就是在修改库存数据的时候,采用锁定状态,排斥外部请求的修改。没有拿到锁的请求,必须等待,这样会不断累积请求,有可能出现死锁,或者系统陷入内存异常。
为了避免在服务器积累太多的请求,我们可以先将请求放入FIFO队列中,等前面的请求处理完,再处理队列中排队的请求,避免太多请求同时进入发生死锁,就不会导致某些请求永远获取不到锁。
高并发的场景下,有可能一瞬间出现大量请求将队列内存撑爆,我们可以设计一个极大的内存队列,但是队列内的请求积累得过多,最终平均响应时延会大幅延长。
乐观锁思路
乐观锁是更为宽松的加锁机制,甚至也可以认为是不加锁。乐观锁的实现通常采用带版本号的CAS操作。所有请求都有资格去修改库存数据,都会获得一个数据的版本号,只有版本号符合的才能更新成功,其他的都抢购失败,这样不需要考虑排队的问题。
很多软件和服务都支持乐观锁的功能,例如Redis中的watch就是其中之一。Redis watch 命令用于监视一个或多个 key。如果在事务执行之前,发现key 被其他命令所改动,那么事务将被打断。通过这种乐观锁的实现方式,我们也可以保证数据的安全。
我会持续更新关于物联网、云原生以及数字科技方面的文章,用简单的语言描述复杂的技术,也会偶尔发表一下对IT产业的看法,欢迎大家关注,谢谢。
相关推荐
- Linux高性能服务器设计
-
C10K和C10M计算机领域的很多技术都是需求推动的,上世纪90年代,由于互联网的飞速发展,网络服务器无法支撑快速增长的用户规模。1999年,DanKegel提出了著名的C10问题:一台服务器上同时...
- 独立游戏开发者常犯的十大错误
-
...
- 学C了一头雾水该咋办?
-
学C了一头雾水该怎么办?最简单的方法就是你再学一遍呗。俗话说熟能生巧,铁杵也能磨成针。但是一味的为学而学,这个好像没什么卵用。为什么学了还是一头雾水,重点就在这,找出为什么会这个样子?1、概念理解不深...
- C++基础语法梳理:inline 内联函数!虚函数可以是内联函数吗?
-
上节我们分析了C++基础语法的const,static以及this指针,那么这节内容我们来看一下inline内联函数吧!inline内联函数...
- C语言实战小游戏:井字棋(三子棋)大战!文内含有源码
-
井字棋是黑白棋的一种。井字棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉、一条龙、三子旗等。将正方形对角线连起来,相对两边依次摆上三个双方棋子,只要将自己的三个棋子走成一条线,对方就算输了。但是,有很多时...
- C++语言到底是不是C语言的超集之一
-
C与C++两个关系亲密的编程语言,它们本质上是两中语言,只是C++语言设计时要求尽可能的兼容C语言特性,因此C语言中99%以上的功能都可以使用C++完成。本文探讨那些存在于C语言中的特性,但是在C++...
- 在C++中,如何避免出现Bug?
-
C++中的主要问题之一是存在大量行为未定义或对程序员来说意外的构造。我们在使用静态分析器检查各种项目时经常会遇到这些问题。但正如我们所知,最佳做法是在编译阶段尽早检测错误。让我们来看看现代C++中的一...
- ESL-通过事件控制FreeSWITCH
-
通过事件提供的最底层控制机制,允许我们有效地利用工具箱,适时选择使用其中的单个工具。FreeSWITCH是一个核心交换与混合矩阵,它周围有几十个模块提供各种功能特性。我们完全控制了所有的即时信息,这些...
- 物理老师教你学C++语言(中篇)
-
一、条件语句与实验判断...
- C语言入门指南
-
当然!以下是关于C语言入门编程的基础介绍和入门建议,希望能帮你顺利起步:C语言入门指南...
- C++选择结构,让程序自动进行决策
-
什么是选择结构?正常的程序都是从上至下顺序执行,这就是顺序结构...
- C++特性使用建议
-
1.引用参数使用引用替代指针且所有不变的引用参数必须加上const。在C语言中,如果函数需要修改变量的值,参数必须为指针,如...
- C++程序员学习Zig指南(中篇)
-
1.复合数据类型结构体与方法的对比C++类:...
- 研一自学C++啃得动吗?
-
研一自学C++啃得动吗?在开始前我有一些资料,是我根据网友给的问题精心整理了一份「C++的资料从专业入门到高级教程」,点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!!个人...
- C++关键字介绍
-
下表列出了C++中的常用关键字,这些关键字不能作为变量名或其他标识符名称。1、autoC++11的auto用于表示变量的自动类型推断。即在声明变量的时候,根据变量初始值的类型自动为此变量选择匹配的...
- 一周热门
-
-
C# 13 和 .NET 9 全知道 :13 使用 ASP.NET Core 构建网站 (1)
-
因果推断Matching方式实现代码 因果推断模型
-
git pull命令使用实例 git pull--rebase
-
git pull 和git fetch 命令分别有什么作用?二者有什么区别?
-
面试官:git pull是哪两个指令的组合?
-
git 执行pull错误如何撤销 git pull fail
-
git fetch 和git pull 的异同 git中fetch和pull的区别
-
git pull 之后本地代码被覆盖 解决方案
-
还可以这样玩?Git基本原理及各种骚操作,涨知识了
-
git命令之pull git.pull
-
- 最近发表
- 标签列表
-
- git pull (33)
- git fetch (35)
- mysql insert (35)
- mysql distinct (37)
- concat_ws (36)
- java continue (36)
- jenkins官网 (37)
- mysql 子查询 (37)
- python元组 (33)
- mysql max (33)
- vba instr (33)
- mybatis 分页 (35)
- vba split (37)
- redis watch (34)
- python list sort (37)
- nvarchar2 (34)
- mysql not null (36)
- hmset (35)
- python telnet (35)
- python readlines() 方法 (36)
- munmap (35)
- docker network create (35)
- redis 集合 (37)
- python sftp (37)
- setpriority (34)