我司小胖问我,什么是悲观锁 & 乐观锁?

简介: 我司小胖问我,什么是悲观锁 & 乐观锁?

悲观锁有 & 乐观锁


首先,悲观锁与乐观锁是根据操作时是否锁住资源来判别的。悲观锁获取到锁时,必须要锁住资源;乐观锁则不会。一开始两线程争抢锁:


640.jpg


悲观锁


悲观锁之所以悲观,那是因为它觉得如果不锁住这个资源,别的线程就会来争抢,造成数据结果错误,所以悲观锁为了确保结果的正确性,会在每次获取并修改数据时,都把数据锁住,让其他线程无法访问该数据,这样就可以确保数据内容万无一失,从这点看悲观锁特别稳。


下面通过几张图,大概就能明白悲观锁的执行过程了:


接上面场景,如果 A 拿到锁,正在操作资源,B 就只能进入等待。


640.jpg


直至 A 执行完毕释放锁,CPU 唤醒等待此锁的线程 B。


640.jpg


线程 B 获取到了锁,就可以对同步资源进行自己的操作。这就是悲观锁的操作流程。


640.jpg


乐观锁


乐观锁顾名思义,比较乐观。相比于悲观锁,它是不锁住资源的,因为它觉得自己在操作资源时并不会有其他线程干扰。


因此,为了保障数据的正确性。它在操作之前,会先判断在自己操作期间,其他线程是否有操作。如果没有,直接操作;如果有,则根据业务选择报错或者重试。


下面来看看,乐观锁的执行过程:


乐观锁的这把锁,其实就是依赖的 CAS (compare and swap:比较并交换)算法。所以,它在操作资源之前并不需要获得锁,直接读取资源到自己的工作内存内操作


640.jpg


操作完成,准备更新资源时。就会触发 CAS 算法,判断资源是否被其他线程修改过。


640.jpg


没有修改过,直接更新,线程执行完毕。


640.jpg


被修改过,根据业务逻辑走下一步,是重试还是报错?


640.jpg


典型应用


值得注意的是,不管是在 Java 还是数据库中都用到了。悲观锁、乐观锁的概念,只是实现方式稍有不同。下面介绍下 Java 中的悲观、乐观锁:


  • 悲观锁:synchronized 关键字和 Lock 接口


这两够经典的,synchronized 必须要获取 mintor 锁才能进去操作资源;Lock 接口也是,必须显示调用 lock 才能操作资源。必须取到锁才能进行操作,这就是悲观锁的思想


  • 乐观锁:原子类


这类应该很常用,比如用作线程间的计数器。典型如 AtomicInteger 类在进行运算时,就使用了乐观锁的思想。使用 compareAndSet 方法更新数据,更新失败则重试。

数据库中的悲观、乐观锁:


  • 典型的 select for update 语句,用的就是悲观锁思想。在提交之前不允许第三方来修改该数据。高并发环境吃不消。


  • 利用 version 字段实现乐观锁,version 代表这条数据的版本。操作数据不需要获取锁,操作完准备更新时。对比版本号是不是和获取数据时一致?是:更新,否:重新计算,再尝试更新。


比如以下的 update 语句:


UPDATE people
SET
name = '狗哥',
    version = 2
WHERE id = 30624700
AND version = 1


使用场景


说了这么久,悲观锁乐观锁的区别我知道了。那这两种锁在啥样的场景下使用呢?


有人说悲观锁比乐观锁消耗大,因为悲观要锁、乐观不要锁(注意,这里我说不要是实际没锁住资源,它的锁其实是 CAS 算法)。是的,如果并发量很小的情况下,悲观锁确实比乐观锁消耗大。但如果并发量很高,导致乐观锁一直在重试,这时它消耗的资源比固定开销的悲观大,也是说不定的。


  • 悲观锁适用于并发写入多,竞争激烈等场景,这些场景下,悲观锁确实会让得不到锁的线程阻塞,但这些开销是固定的。它可以避免后面更新时的无用反复尝试操作,节约开销。


  • 乐观锁适用于大部分是读取,少部分是修改的场景,也适合虽然读写都很多,但是并发并不激烈的场景。在这些场景下,乐观锁不加锁的特点能让性能大幅提高。
相关文章
|
17天前
|
算法 关系型数据库 MySQL
|
3月前
|
算法 Java 关系型数据库
面试必备之何谓悲观锁与乐观锁
乐观锁对应于生活中乐观的人总是想着事情往好的方向发展,悲观锁对应于生活中悲观的人总是想着事情往坏的方向发展。这两种人各有优缺点,不能不以场景而定说一种人好于另外一种人。
28 1
|
7月前
|
安全 数据库
什么是计算机编程领域的乐观锁和悲观锁
什么是计算机编程领域的乐观锁和悲观锁
34 0
|
7月前
|
消息中间件 缓存 安全
Eureka这波加锁操作让我惊呆了
在对于读写锁的认识当中,我们都认为读时加读锁,写时加写锁来保证读写和写写互斥,从而达到读写安全的目的。但是就在我翻Eureka源码的时候,发现Eureka在使用读写锁时竟然是在读时加写锁,写时加读锁,这波操作属实震惊到了我,于是我就花了点时间研究了一下Eureka的这波操作。
|
8月前
|
NoSQL Java Redis
得不到你的心,就用“分布式锁”锁住你的人 码农在囧途
朋友,如果喜欢,就去表白吧,不要因为害羞,更不要因为自卑,如果现在你都还不敢表白,那么多年后,再回头来看的时候,你可能会为曾经的胆小而后悔,也可能会为错过一个人而心中久久不能释怀,所以,大胆一点,即使失败也无所谓,至少我们曾经做过,做过了就无怨无悔,在人生这条道路上,时光稍纵即逝,我们应该把握好眼前的一切,爱是一种力量,更是一种内心的慰藉,冲吧!不要因为钱不够,不要因为容貌不出中国,更不要因为身世不显赫,你只要足够勇敢,这一切都是附加品!
78 0
|
10月前
|
XML 前端开发 Java
案例突破——悲观锁和乐观锁
案例突破——悲观锁和乐观锁
99 0
案例突破——悲观锁和乐观锁
|
11月前
|
算法 Java 关系型数据库
同步锁、死锁、乐观锁、悲观锁 (高薪常问)
同步锁、死锁、乐观锁、悲观锁 (高薪常问)
69 2
|
11月前
|
算法 Java 关系型数据库
面试乐观锁悲观锁如何回答?
面试乐观锁悲观锁如何回答?
47 0
|
11月前
|
算法 Java 关系型数据库
何谓悲观锁与乐观锁
何谓悲观锁与乐观锁
|
Java 关系型数据库 程序员
深入浅出乐观锁、悲观锁
深入浅出乐观锁、悲观锁
深入浅出乐观锁、悲观锁