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

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

悲观锁有 & 乐观锁


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


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 算法)。是的,如果并发量很小的情况下,悲观锁确实比乐观锁消耗大。但如果并发量很高,导致乐观锁一直在重试,这时它消耗的资源比固定开销的悲观大,也是说不定的。


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


  • 乐观锁适用于大部分是读取,少部分是修改的场景,也适合虽然读写都很多,但是并发并不激烈的场景。在这些场景下,乐观锁不加锁的特点能让性能大幅提高。
相关文章
|
XML Java 数据格式
Springboot中自定义组件
Springboot中自定义组件
180 1
|
存储 关系型数据库 MySQL
MySQL中的回表
MySQL中的回表
|
Java 数据库连接
什么是双亲委派?如何打破双亲委派?
什么是双亲委派?如何打破双亲委派?
299 0
|
存储 SQL Java
好多人都说存储过程很难?认真看这篇文章就够了
好多人都说存储过程很难?认真看这篇文章就够了
|
4月前
|
安全 Java 数据库
使用Java实现用户的注册和登录流程
以上提供了用户注册和登录的基本框架和必要的说明。在具体的应用场景中,可能还需结合框架特性如Spring Security等提供的高级特性来实现更为完备和安全的用户认证机制。在开发期间,务必注重代码的安全性、清晰性和可维护性,为用户资料保驾护航。
310 13
|
7月前
|
存储 SQL 关系型数据库
MySQL 中的回表是什么?
在 MySQL 中,“回表”是指通过二级索引查询时,因二级索引仅存储索引字段值和主键值,需再根据主键到聚簇索引查找完整行数据的过程。此操作涉及两次索引查找,可能增加 IO 消耗,影响性能。优化方法包括使用覆盖索引或联合索引,避免回表,提升查询效率。合理设计索引对高并发、大数据量场景下的数据库性能至关重要。
414 17
|
5月前
|
消息中间件 存储 大数据
阿里云消息队列 Kafka 架构及典型应用场景
阿里云消息队列 Kafka 是一款基于 Apache Kafka 的分布式消息中间件,支持消息发布与订阅模型,满足微服务解耦、大数据处理及实时流数据分析需求。其通过存算分离架构优化成本与性能,提供基础版、标准版和专业版三种 Serverless 版本,分别适用于不同业务场景,最高 SLA 达 99.99%。阿里云 Kafka 还具备弹性扩容、多可用区部署、冷热数据缓存隔离等特性,并支持与 Flink、MaxCompute 等生态工具无缝集成,广泛应用于用户行为分析、数据入库等场景,显著提升数据处理效率与实时性。
|
8月前
|
存储 安全
ArrayList 和 LinkedList 的区别是什么?
1. 数据结构实现:ArrayList 是动态数组的数据结构实现,而 LinkedList 是双向链表的数据结构实 现。 2. 随机访问效率:ArrayList 比 LinkedList 在随机访问的时候效率要高,因为 LinkedList 是线性的数 据存储方式,所以需要移动指针从前往后依次查找。 3. 增加和删除效率:在非首尾的增加和删除操作,LinkedList 要比 ArrayList 效率要高,因为 ArrayList 增删操作要影响数组内的其他数据的下标。 4. 内存空间占用:LinkedList 比 ArrayList 更占内存,因为 LinkedList 的节点除了存储数
|
安全 Java 程序员
Spring框架的核心特性是什么?
【4月更文挑战第30天】Spring 的特性
1014 0
|
关系型数据库 MySQL 分布式数据库
Hbase与MySQL对比,区别是什么?
Hbase与MySQL对比,区别是什么?
861 2