什么是乐观锁和悲观锁-程序员宅基地

技术标签: java基础  Mysql  乐观锁  悲观锁  

一、什么是乐观锁

乐观锁,顾名思义就是总是假设最好的情况,每次获取数据的时候都认为别人不会修改,所以不会上 锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和 CAS 算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于 write_condition 机制,其实都是提供的乐观锁。在 Java 中 java.util.concurrent.atomic 包下面的原子变量类就是使用了乐观锁的一种实现方式 CAS 实现的。 

二、什么是悲观锁

悲观锁,顾名思义就是总是假设最坏的情况,每次获取数据的时候都认为别人会修改,所以每次在获取数据的时候都会上锁,这样别人想获取这个数据就会阻塞直到它拿到锁后才可以获取(共享资源每次只给一个线程使用,其它线程阻塞,当前线程用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁、表锁、读锁、写锁等,都是在做操作之前先上锁。Java 中 synchronized 和 ReentrantLock 等独占锁就是悲观锁思想的实现。

三、两种锁的使用场景

  从上面对两种锁的介绍,我们知道两种锁各有优缺点,我们不可以简单的认为它们哪一种更好 ,像乐观锁适用于写比较少的情况下(多读场景),即实际冲突很少发生的 时候,这样可以省去加锁造成的开销,加大了系统的整个吞吐量。但如果是在多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行重试,这样反倒是降低了性能,所以一般在多写的场景下使用悲观锁就比较合适。   

四、乐观锁常见的两种实现方式

乐观锁一般会使用版本号机制或 CAS 算法实现。
 
(1)版本号机制
   一般是在数据表中加上一个数据版本号 version 字段,表示数据被修改的次数,当数据被修改时,version 值会加一。当线程 A 要更新数据值时,在读取数据的同时也会读取 version 值,在提交更新时,若刚才读取到的 version 值与当前数据库中的 version 值相等时才更新,否则将会重试更新操作,直到更新成功。
这里举一个简单的例子进行说明:
假设数据库中帐户信息表中有一个 version 字段,当前值为 1 ;而当前帐户余额字段(balance)为 $100 。
① 操作员 A 此时将其读出(version=1),并从其帐户余额中扣除 $50($100-$50)。
② 在操作员 A 操作的过程中,操作员 B 也读入此用户信息(version=1),并从其帐户余额中扣除 $20($100-$20)。
③ 操作员 A 完成了修改工作,将数据版本号加一(version=2),连同帐户扣除后余额(balance=$50),提交至数据库更新,此时由于提交数据版本大于数据库记录当前版本,数据被更新,数据库记录 version 更新为 2 。
④ 操作员 B 完成了操作,也将版本号加一(version=2)试图向数据库提交数据(balance=$80),但此时比对数据库记录版本时发现,操作员 B 提交的数据版本号为 2 ,数据库记录当前版本也为 2 ,不满足 “ 提交版本必须大于记录当前版本才能执行更新 “ 的乐观锁策略,
因此,操作员 B 的提交被驳回。这样就避免了操作员 B 用基于 ver sion=1 的旧数据修改的结果覆盖操作员 A 的操作结果的可能。    
 
(2)CAS算法
compare and swap (比较与交换) ,是一种有名的 无锁算法 。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。
CAS 算法 涉及到三个操作数:
① 需要读写的内存值 V
② 进行比较的值
A
③ 拟写入的新值
B
当且仅当 V 的值等于 A 时, CAS 通过原子方式用新值 B 来更新 V 的值,否则不会执行任何操作(比较和替换是一个原子操作)。一般情况下是一个自旋操作,即 不断的重试。

五、乐观锁的缺点

(1)ABA 问题
ABA 问题是乐观锁的一个常见问题。如果一个变量 V 初次读取的时候是 A 值,并且在准备赋值的时候检查到它仍然是 A 值,那我们就能说明它的值没有被其他线程修改过了吗?很明显是不能的,因为在这段时间它的值可能被改为其他值,然后又改回 A,那 CAS 操作就会误认为它从来没有被修改过。这个问题被称为 CAS 操作的 "ABA" 问题。
 
JDK 1.5 以后的 AtomicStampedReference 类就提供了解决 ABA 问题的方法,其中的 compareAndSet 方法就是首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。
 
(2)循环时间长开销大
自旋 CAS (也就是更新不成功就一直循环执行直到成功)如果长时间不成功,会给CPU 带来非常大的执行开销。 如果 JVM 能支持处理器提供的 pause 指令那么效率会有一定的提升,pause 指令有两个作用,第一它可以延迟流水线执行指令(de-pipeline ), 使 CPU 不会消耗过多的执行资源,延迟的时间取决于具体实现的版本,在一些处理器上延迟时间是零。第二它可以避免在退出循环的时候因内存顺序冲突(memory order violation )而引起 CPU 流水线被清空(CPU pipeline flush ),从而提高 CPU 的执行效率。
 
(3) 只能保证一个共享变量的原子操作
CAS 只对单个共享变量有效,当操作涉及跨多个共享变量时 CAS 无效。但是从 JDK 1.5 开始,提供了 AtomicReference 来保证引用对象之间的原子性,你可以把多个变量放在一个对象里来进行 CAS 操作。 所以我们可以使用锁或者利用 AtomicReference 把多个共享变量合并成一个共享变量来操作。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_48016395/article/details/124068012

智能推荐

使用选项卡创建CSS3 / jQuery跨浏览器下拉菜单-程序员宅基地

文章浏览阅读126次。CSS3/jQuery dropdown menu with tabs tutorial. This is our seventh CSS3 menu. Today we will make dropdown menu with parental tabs (as first level). Part of the work we pass on to the shoulders of jQuer..._./images/tabs/left_memu_1.png

Hypack 2016-2018设置使用测试与相关下载_hypack2016-程序员宅基地

文章浏览阅读2.3k次,点赞2次,收藏9次。Hypack 2016-2018使用测试与相关下载1、hypack 2016、hypack 2017、hypack2018通过现场使用测试,发现64位版本破解无效,32位破解成功。2、Hypack 6.2以前的版本,导航硬件典型配置库文件为nmea.DLL。(配置为nmea.DLL输出WGS84与本地54坐标XY出现错误)3、Hypack 2016-2018版本导航硬件配置库文件应该采用G..._hypack2016

CiteSpace使用入门教程_citespace怎么用-程序员宅基地

文章浏览阅读8.1k次,点赞4次,收藏17次。CiteSpace软件的使用及应用_citespace怎么用

这6种最佳移动自动化测试工具你知道吗?_移动应用测试工具有哪些-程序员宅基地

文章浏览阅读1k次。它还带有一个客户端库的特性,可以托管 Java、Python、C# 等中的锅炉代码,以帮助 QA 更快、更有效地开发测试脚本。testRigor 是超级可靠的,因为它为人类各自创建了一个测试套件,也就是说,它不依赖于 XPath 之类的源。它是一个基于云的移动自动化测试工具,允许用户在各种设备和操作系统版本上以连续的时间间隔快速运行测试。总而言之,它是一个很好的工具,但既不是免费的也不是开源的。ZAPTEST 的卖点是它的投资回报率计算器,它允许像您这样的企业计算这种自动化工具的投资回报率。_移动应用测试工具有哪些

分类预测 | Matlab实现CNN-LSTM-Mutilhead-Attention卷积神经网络-长短期记忆网络融合多头注意力机制多特征分类预测_nn.multiheadattention 图像分类-程序员宅基地

文章浏览阅读1.1k次,点赞21次,收藏12次。分类预测 | Matlab实现CNN-LSTM-Mutilhead-Attention卷积神经网络-长短期记忆网络融合多头注意力机制多特征分类预测_nn.multiheadattention 图像分类

对称加密、非对称加密、公钥、私钥究竟是个啥?_非对称加密,私钥公钥成对生成是啥意思-程序员宅基地

文章浏览阅读1.3w次,点赞72次,收藏247次。世界上有没有不能破解的密码或加密方式?还真有一种,叫做一次性密码本,这时唯一一种不能破解的加密方式,而其他的密码只要时间无限理论上都是可破解的,如果你也对加密这个领域感兴趣,可以简单了解下这些概念..._非对称加密,私钥公钥成对生成是啥意思

随便推点

vue3的代码改成vue2的转换_vue3组件 转 vue2-程序员宅基地

文章浏览阅读8.7k次。vue3<!DOCTYPE html><html><head><meta charset="utf-8"><title>Vue的方法_侠课岛(9xkd.com)</title><script src="https://unpkg.com/vue@next"></script></head><body> <div id="hello-vue" class="_vue3组件 转 vue2

vue2.0与支付个人总结-程序员宅基地

文章浏览阅读275次。最近在使用vue写webapp,app中要求可以实现线上支付,研究了微信H5支付与支付宝H5支付。其中微信H5支付处在内测阶段,需要申请,按照格式写了邮件七个工作日也没得到回复邮件,据说微信H5支付对于单量和交易额有要求,满足要求后才有很大几率开通。支付宝H5支付相对申请较为简单,人工技术客服强大,基本能解决很多问题,不得不说这点还是阿里..._vue2.0 调用app支付

yml配置文件中map的配置-程序员宅基地

文章浏览阅读6.5k次。yml中map的配置文件

python中摄氏度的符号咋打_linux下怎么方便的输入度数符号 °-程序员宅基地

文章浏览阅读5k次。你的位置:问答吧-> Linux 入门-> 问题详情linux下怎么方便的输入度数符号 °在windows下可以用Alt 0176输入,在MAC下也有方便的方法可以输入,在linux下呢?参见:http://anonymouse.org/cgi-bin/anon-w...egree_(symbol)作者: mu..._linux 输入法 摄氏度

Java面试题之接口和抽象类的区别_java面试题 接口和抽象类的区别-程序员宅基地

文章浏览阅读706次。下面一些东西可能会让你不敢相信,这次分为jdk8和jdk9来测试的,大家也可以用不同的jdk尝试一下。先说一下基本的定义,在说一下特别的东西。有疑惑的同学一定要去自己手动的试验一下,加深印象,面试官比如说接口中的方法不能有方法体啊什么的,一定坚定告诉他是可以的!一个类可以同时实现多个接口 一个抽象类只能继承一个类(单继承)接口和接口之间支持多继承 类和类之间只能单继承。抽象类是半抽象的 接口是完全抽象的。_java面试题 接口和抽象类的区别

Machine and Deep Learning with Python-程序员宅基地

文章浏览阅读407次。Machine and Deep Learning with PythonEducationTutorials and coursesSupervised learning superstitions cheat sheetIntroduction to Deep Learning with PythonHow to implement a neural network..._pyqtgraph eeg

推荐文章

热门文章

相关标签