面试中的最常被问到的两种锁

简介: 之前在的文章中已经写了公平锁、非公平锁,独享锁、共享锁,互斥锁和读写锁,那么接下来我们就得介绍互乐观锁和悲观锁了。那我们我就来了解一波把!

锁的分类

1.公平锁/非公平锁

2.可重入锁
3.独享锁/共享锁
4.互斥锁/读写锁
5.乐观锁/悲观锁
6.分段锁
7.偏向锁/轻量级锁/重量级锁
8.自旋锁


乐观锁(Optimistic Locking)

所谓的乐观,实际上是相对于悲观锁来说,我们先看一下百度百科中的解释。

乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库 性能的大量开销, 特别是对长事务而言,这样的开销往往无法承受。相对悲观锁而言,乐观锁更倾向于开发运用。

上面的内容都是乐观锁在百度百科中的解释,我们如果想要理解这个锁,是需要我们去找一个场景来进行解释的。

我们就从最经典的案例“老王取钱”来说,

11.jpg

1图中有三个存在,分别表示老王,和老王账户,还有一个就是版本信息。版本信息默认是1,这时候老王要买点东西,结果发现钱不太够,那就去银行取点钱去呗,果断的来了银行。

12.jpg

然后告诉柜员,取5000块钱,然后柜员就会从他的账户余额里面扣除5000,就是-5000

13.jpg


这时候版本信息是1,但是我们对金额做了修改之后,要把版本信息换成2,因为现在保存的版本信息是1,柜员查看的时候也是1,老王取钱了, 就想着修改成2。

但是,就在这个时候,来事了,老王的媳妇出去买衣服,发现身上钱不太够,就打算取点钱,就来了另外一家银行,这时候老王钱拿到了,但是柜员还没修改版本信息

就是这样子的,

14.jpg

这时候告诉柜员要取钱,柜员就回去读卡了,发现版本信息是1,

15.jpg

然后就在这时候,老王这头,柜员打算把这-5000的操作记录到数据库中,然后把版本信息变成2,这时候校验数据库中的版本信息还是1,所以, 录入成功了,就稳定的把这个信息改成了2,这时候就是这样的

16.jpg

钱也到手了,老王美滋滋的拿钱走了。

然后在老王媳妇这边的柜员在操作的时候就会出现问题了,之前读出来的账户信息版本是1,但是他要去操作的时候,发现不对呀,有人修改过呀, 就会出现这种情况。

17.jpg但是他想去修改的时候人家现在默认的是2,这时候他在比对的时候是1和2了,然后就想着在次提交,这时候,操作完成不了,这就太尴尬了

这种情况就是证明不能让老王媳妇这边的柜员,拿着一版本的数据去吧老王那边的数据覆盖掉。这种其实就相当于是一种乐观锁的提现。


上面的图解就是乐观锁,

乐观锁,大多是基于数据版本( Version )记录机制实现。 何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个 “version” 字段来实现。 读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对, 如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。



那什么又是悲观锁呢?我们接下来在说说什么是悲观锁。

悲观锁

惯例,先来看看百度百科中的解释

悲观锁,正如其名,具有强烈的独占和排他特性。它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度, 因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性, 否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。


因为悲观锁总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。


案例来袭:“工资的那点事”

这天老王开工资了,工资已经到账了,这时候老王没开短信提醒,得去看看钱到还是没到?

18.jpg

然后就告诉柜员,帮我查查卡里有多少钱?

19.jpg

正在柜员查钱的时候,老王媳妇又来取钱了,上次买的衣服不好看,再买点,钱不够就来银行了。

20.jpg

这时候老王正在查钱,而悲观锁的意思就是我在读的时候,我是锁着的你是看不到的,可以这么理解。

21.jpg

这时候老王媳妇就处于等待的状态,这个样子就是相当于悲观锁。

因为悲观锁就是当我们去获取数据的时候,不论我们有没有打算去修改,悲观锁都会认为我们一定会去修改这个数据,所以 他会把这个数据直接锁死,其他的人想操作操作,那你就阻塞,直到轮到你获取锁为止。


悲观锁和乐观锁的区别也就在这里。

乐观锁 总是认为不会产生并发问题,每次去取数据的时候总认为不会有其他线程对数据进行修改,因此不会上锁,但是在更新时会判断其他线程在这之前有没有对数据进行修改,一般会使用版本号机制或CAS操作实现。


悲观锁总是假设最坏的情况,每次取数据时都认为其他线程会修改,所以都会加锁(读锁、写锁、行锁等),当其他线程想要访问数据时,都需要阻塞挂起

关于乐观锁和悲观锁,你了解了么?

相关文章
|
3月前
|
NoSQL Java API
美团面试:Redis锁如何续期?Redis锁超时,任务没完怎么办?
在40岁老架构师尼恩的读者交流群中,近期有小伙伴在面试一线互联网企业时遇到了关于Redis分布式锁过期及自动续期的问题。尼恩对此进行了系统化的梳理,介绍了两种核心解决方案:一是通过增加版本号实现乐观锁,二是利用watch dog自动续期机制。后者通过后台线程定期检查锁的状态并在必要时延长锁的过期时间,确保锁不会因超时而意外释放。尼恩还分享了详细的代码实现和原理分析,帮助读者深入理解并掌握这些技术点,以便在面试中自信应对相关问题。更多技术细节和面试准备资料可在尼恩的技术文章和《尼恩Java面试宝典》中获取。
美团面试:Redis锁如何续期?Redis锁超时,任务没完怎么办?
|
4月前
|
消息中间件 安全 前端开发
面试官:单核服务器可以不加锁吗?
面试官:单核服务器可以不加锁吗?
62 4
面试官:单核服务器可以不加锁吗?
|
4月前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
|
3月前
|
存储 Kubernetes 架构师
阿里面试:JVM 锁内存 是怎么变化的? JVM 锁的膨胀过程 ?
尼恩,一位经验丰富的40岁老架构师,通过其读者交流群分享了一系列关于JVM锁的深度解析,包括偏向锁、轻量级锁、自旋锁和重量级锁的概念、内存结构变化及锁膨胀流程。这些内容不仅帮助群内的小伙伴们顺利通过了多家一线互联网企业的面试,还整理成了《尼恩Java面试宝典》等技术资料,助力更多开发者提升技术水平,实现职业逆袭。尼恩强调,掌握这些核心知识点不仅能提高面试成功率,还能在实际工作中更好地应对高并发场景下的性能优化问题。
|
5月前
|
存储 安全 容器
【多线程面试题二十一】、 分段锁是怎么实现的?
这篇文章解释了分段锁的概念和实现方式,通过将数据分成多个段并在每段数据上使用独立锁,从而降低锁竞争,提高并发访问效率,举例说明了`ConcurrentHashMap`如何使用分段锁技术来实现高并发和线程安全。
【多线程面试题二十一】、 分段锁是怎么实现的?
|
5月前
|
缓存 Java
【多线程面试题二十三】、 说说你对读写锁的了解volatile关键字有什么用?
这篇文章讨论了Java中的`volatile`关键字,解释了它如何保证变量的可见性和禁止指令重排,以及它不能保证复合操作的原子性。
|
5月前
|
Java
【多线程面试题二十二】、 说说你对读写锁的了解
这篇文章讨论了读写锁(ReadWriteLock)的概念和应用场景,强调了读写锁适用于读操作远多于写操作的情况,并介绍了Java中`ReentrantReadWriteLock`实现的读写锁特性,包括公平性选择、可重入和可降级。
|
5月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
2月前
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
2月前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?

热门文章

最新文章