在介绍悲观锁和乐观锁之前,我们先看一下什么是锁。

生活中:锁在我们身边无处不在,比如我出门玩去了需要把门锁上,比如我需要把钱放到保险柜里面,必须上锁以保证我财产的安全。

代码中:比如多个线程需要同时操作修改共享变量,这时需要给变量上把锁(syncronized),保证变量值是对的。

数据库表:当多个用户修改表中同一数据时,我们可以给该行数据上锁(行锁)。

悲观锁(悲观并发控制)

当我们要对数据库中的一条数据进行修改的时候,为了避免同时被其他人修改,最好的办法就是直接对该数据进行加锁以防止并发的发生。

为什么叫做悲观锁呢?因为这是一种对数据的修改抱有悲观态度的并发控制方式。我们一般认为数据被并发修改的概率比较大,所以需要在修改之前先加锁。

数据库中的行锁,表锁,读锁,写锁,以及 syncronized 实现的锁均为悲观锁。

乐观锁

乐观锁是对于数据冲突保持一种乐观态度,操作数据时不会对操作的数据进行加锁,只有到数据提交的时候才通过一种机制来验证数据是否存在冲突。

乐观锁通常是通过在表中增加一个版本(version)或时间戳(timestamp)来实现,其中,版本最为常用。

乐观锁每次在执行数据的修改操作时,都会带上一个版本号,一旦版本号和数据的版本号一致就可以执行修改操作并对版本号执行 +1 操作,否则就执行失败。

如何实现

我们知道悲观锁和乐观锁是用来控制并发下数据的顺序变动问题的。那么我们就模拟一个需要加锁的场景,来看不加锁会出什么问题,并且怎么利用悲观锁和乐观锁去解决。

我们以商品为例,现在 线程A 和线程 B 都想吃红薯,但是红薯数量只有 1 个了。在不加锁的情况下,如果A,B同时下单,就有可能导致超卖。

悲观锁实现

利用悲观锁的解决思路是,我们认为数据修改产生冲突的概率比较大,所以在更新之前,我们显示的对要修改的记录进行加锁,直到自己修改完再释放锁。加锁期间只有自己可以进行读写,其他事务只能读不能写。

此时线程 A 下单前先给红薯这行数据(id=C001)加上悲观锁(行锁)。此时这行数据只能 A 来操作,也就是只有 A 能买。B 想买就必须一直等待。当 A 买好后,B 再想去买的时候会发现库存数量已经为 0,那么 B 看到后就会放弃购买。

那怎么样给这行数据加上悲观锁呢?当然是在select给这行数据加上锁,如下所示:

select num from commodity where id = C001 for update

悲观锁图解:

乐观锁解实现

下面我们利用乐观锁来解决该问题。上面乐观锁的介绍中,我们提到了,乐观锁是通过版本号 version 来实现的。所以,我们需要给 commodity 表加上 version 字段。

我们认为数据修改产生冲突的概率并不大,多个线程在修改数据的之前先查出版本号,在修改时把当前版本号作为修改条件,只会有一个线程可以修改成功,其他线程则会失败。

A 和 B 同时将红薯(id=C001)的数据查出来,然后 A 先买,A 将 id=C001 和 version=0 作为条件进行数据更新,即将数量 -1,并且将版本号+1。

此时版本号变为 1。A 此时就完成了商品的购买。最后 B 开始买,B 也将 id=C001 和 version=0 作为条件进行数据更新,但是更新完后,发现更新的数据的库存为 0,此时就说明已经有人修改过数据,此时就应该提示用户重新查看最新数据购买。

乐观锁图解:

如何选择

  • 乐观锁适用于读多写少的场景,可以省去频繁加锁、释放锁的开销,提高吞吐量
  • 在写比较多的场景下,乐观锁会因为版本不一致,不断重试更新,产生大量自旋,消耗 CPU,影响性能。这种情况下,适合悲观锁

什么是乐观锁、悲观锁相关推荐

  1. Java锁详解:“独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁+线程锁”

    在Java并发场景中,会涉及到各种各样的锁如公平锁,乐观锁,悲观锁等等,这篇文章介绍各种锁的分类: 公平锁/非公平锁 可重入锁 独享锁/共享锁 乐观锁/悲观锁 分段锁 自旋锁 线程锁 乐观锁 VS 悲 ...

  2. Mysql之乐观锁悲观锁:乐观锁检查数据状态 悲观锁更新时锁定数据

    1.问题来源 就是一数据表的数据  在两个人同时修改的时候  会出现混乱 例子:如一个字段记录status=1 表示可以下单  货品只有1个的时候    a下单的同时b也下单 : a有修改status ...

  3. Django - ORM - 事务, 乐观锁, 悲观锁

    事务 概念 Transaction 事务:一个最小的不可再分的工作单元:通常一个事务对应一个完整的业务(例如银行账户转账业务,该业务就是一个最小的工作单元) 一个完整的业务需要批量的DML(inser ...

  4. mysql默认乐观锁悲观锁_MySQL中悲观锁和乐观锁到底是什么?-阿里云开发者社区...

    索引和锁是数据库中的两个核心知识点,隔离级别的实现都是通过锁来完成的 按照锁颗粒对锁进行划分 ? 锁用来对数据进行锁定,我们可以从锁定对象的粒度大小来对锁进行划分,分别为行锁.页锁和表锁. 行锁就是按 ...

  5. 最全Java锁详解:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁

    在Java并发场景中,会涉及到各种各样的锁,比如:高并发编程系列:4种常用Java线程锁的特点,性能比较.使用场景,这些锁有对应的种类:公平锁,乐观锁,悲观锁等等,这篇文章来详细介绍各种锁的分类: 公 ...

  6. MySQL - 行锁 表锁 乐观锁 悲观锁 读锁 写锁

    MySQL - 行锁 表锁 乐观锁 悲观锁 读锁 写锁 锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的满足.在DBMS中,可以按照锁的粒度把数据库锁分为行级锁(I ...

  7. 可重入锁/不可重入锁,公平锁/非公平锁,乐观锁/悲观锁,独享锁/共享锁,偏向锁/轻量级锁/重量级锁,分段锁,自旋锁

    在并发编程中,会涉及到各种各样的锁,这篇文章主要介绍各种锁的分类以及作用. 介绍的内容如下: 可重入锁/不可重入锁 公平锁/非公平锁 乐观锁/悲观锁 独享锁/共享锁 偏向锁/轻量级锁/重量级锁 分段锁 ...

  8. 【Redis】事物和锁机制乐观锁悲观锁

    目录 1. Redis 的事务定义 2. Multi.Exec.discard 3. 事务的错误处理 4. 事务冲突的问题 悲观锁 乐观锁 1. Redis 的事务定义 Redis 事务是一个单独的隔 ...

  9. Java 面试 :乐观锁 悲观锁

    乐观锁悲观锁,是为了解决多线程并发操作共享变量可能导致的脏读.幻读和不可重复读等问题 悲观锁 悲观锁,是因为这是一种对数据的修改持有悲观态度的并发控制方式.总是假设最坏的情况,每次读取数据的时候都默认 ...

  10. 悲观锁的实现方式java_并发编程--锁--悲观锁和乐观锁

    悲观锁和乐观锁并不是某个具体的"锁"而是一种并发编程的基本概念,是根据看待并发同步的角度.乐观锁和悲观锁最早出现在数据库的设计当中,后来逐渐被 Java 的并发包所引入. 悲观锁 ...

最新文章

  1. centos设置固定IP方法
  2. lm723大电流可调电源电路图_TE:大电流电源连接器
  3. python解析树_如何使用python中的stanford解析器获取树的叶子?
  4. Oracle收购云安全创企Palerra,以加强安全堆栈
  5. Hulu 视频QoS优化策略
  6. C# out的使用 利用参数返回一个值
  7. PHP. 02®. Ajax异步处理、常见的响应状态、XMLHttpRequest对象及API、ajax的get/post方法、...
  8. php 图片保存到本地文件,php 远程图片保存到本地的函数类
  9. 2018牛客网暑假ACM多校训练赛(第六场)I Team Rocket 线段树
  10. linux 与 windows操作系统的区别
  11. 产品经理/总监 面试题及答案
  12. Linux如何进BIOS看硬盘,bios模式下怎么看硬盘
  13. linux嵌入式做智能家居,嵌入式系统在智能家居中的应用
  14. USB-PPI数据电缆驱动
  15. i310100f和i310105f有什么区别 i3 10100f和i3 10105f 选哪个好
  16. MAMP配置虚拟主机
  17. 【产品运营从0到1】资深产品运营推荐的互联网产品运营人员必看书籍
  18. url action editor 快速修改swf链接
  19. 程序员为什么要时刻保持危机感?
  20. sysctl设置系统参数

热门文章

  1. 自定义TabLayout的下划线的长度
  2. 打破中国企业类软件成长的怪圈,我找到了方法!
  3. Eclipse 项目导航字体设置 左侧树字体 小技巧
  4. Canal1.1.4的安装与使用
  5. css 文本超出隐藏显示省略号
  6. raid 物理盘缓存状态_MegaCli 监控raid状态
  7. WINCE USB摄像头驱动终于初步完成了!!
  8. CRT进入数据库命令
  9. mysql 字符集等设置_MySQL字符集设置
  10. 银行业务知识学习2(银行资本管理)