悲观锁与乐观锁

悲观锁

概念

悲观锁的核心思想是 "悲观" 地认为在对共享资源进行操作时,一定会有其他线程或事务来修改该资源。所以在操作之前,会先对资源进行加锁,以防止其他线程或事务的干扰,确保操作的独占性。

实现方式
  • 数据库层面 :在数据库中,常用的悲观锁实现方式是使用 FOR UPDATE 语句。例如,在 MySQL 中,执行 SELECT ... FOR UPDATE 语句会对查询结果中的记录加上行级锁,其他事务在这些记录被锁定期间无法对其进行修改或删除操作,直到当前事务提交或回滚释放锁。

sql

复制代码
-- 假设在一个事务中执行以下语句
START TRANSACTION;
SELECT * FROM users WHERE id = 1 FOR UPDATE;
-- 对查询到的记录进行修改操作
UPDATE users SET balance = balance - 100 WHERE id = 1;
COMMIT;
  • 编程语言层面 :在 Java 中,synchronized 关键字和 ReentrantLock 类都可以实现悲观锁。synchronized 关键字可以修饰方法或代码块,当一个线程进入被 synchronized 修饰的方法或代码块时,会自动获取锁,其他线程需要等待该线程释放锁才能进入。

java

复制代码
public class PessimisticLockExample {
    private int count = 0;
    private final Object lock = new Object();

    public void increment() {
        synchronized (lock) {
            count++;
        }
    }
}
使用场景

悲观锁适用于写操作频繁、冲突可能性较高的场景。例如,在银行系统中,对用户账户余额的修改操作通常使用悲观锁,以确保在一个事务对账户进行修改时,不会有其他事务同时修改该账户,避免出现数据不一致的问题。

乐观锁

概念

乐观锁持有 "乐观" 的态度,它认为在大多数情况下,多个线程或事务对共享资源的操作不会发生冲突,所以在操作之前不会加锁。只有在更新资源时,才会检查该资源是否被其他线程或事务修改过,如果没有被修改,则进行更新操作;如果被修改了,则采取相应的处理措施,如重试或报错。

实现方式
  • 版本号机制:在数据库表中增加一个版本号字段(通常为整数类型),每次对记录进行修改时,版本号会加 1。在更新记录时,会比较当前版本号与数据库中记录的版本号是否一致,如果一致则更新记录并将版本号加 1,如果不一致则表示记录已被其他事务修改,更新失败。

sql

复制代码
-- 假设 users 表中有 id、balance 和 version 字段
-- 查询记录并获取当前版本号
SELECT id, balance, version FROM users WHERE id = 1;
-- 更新记录时检查版本号
UPDATE users SET balance = balance - 100, version = version + 1 WHERE id = 1 AND version = 1;
  • 时间戳机制:与版本号机制类似,只是使用时间戳来代替版本号。每次对记录进行修改时,会更新记录的时间戳。在更新记录时,会比较当前时间戳与数据库中记录的时间戳是否一致。
使用场景

乐观锁适用于读操作频繁、写操作较少、冲突可能性较低的场景。例如,在电商系统中,商品的库存信息通常会被大量用户读取,但只有在用户下单时才会进行写操作,这种情况下可以使用乐观锁来提高系统的并发性能。

对比

  • 性能方面:悲观锁由于在操作之前就加锁,会导致其他线程或事务需要等待锁的释放,可能会降低系统的并发性能。而乐观锁在大多数情况下不需要加锁,只有在更新时才进行检查,因此在并发度较高的场景下,乐观锁的性能通常优于悲观锁。
  • 冲突处理:悲观锁通过加锁来避免冲突,保证了数据的一致性,但会增加死锁的风险。乐观锁在冲突发生时,需要进行额外的处理,如重试或报错,可能会导致一定的性能开销。
  • 使用场景:悲观锁适用于写操作频繁、冲突可能性较高的场景,而乐观锁适用于读操作频繁、写操作较少、冲突可能性较低的场景。
相关推荐
Dcs19 分钟前
代码评审还能更好!
java
刃神太酷啦32 分钟前
C++ 异常处理机制:从基础到实践的全面解析----《Hello C++ Wrold!》(20)--(C/C++)
java·c语言·开发语言·c++·qt·算法·leetcode
蓝倾97633 分钟前
小红书获取用户作品列表API接口操作指南
java·服务器·前端·python·电商开放平台·开放api接口
ITZHIHONH34 分钟前
FastGPT源码解析 Agent知识库文本资料处理详解和代码分析
数据库·ai编程
Seven9739 分钟前
剑指offer-28、数组中出现次数超过⼀半的数字
java
浮游本尊40 分钟前
Java学习第19天 - 分布式缓存与Redis高级应用
java
bemyrunningdog1 小时前
DTO与POJO:核心差异与最佳实践
java
en-route1 小时前
深入理解 MDC(Mapped Diagnostic Context):日志记录的利器
java·log4j
一叶飘零_sweeeet1 小时前
SpringBoot 数据脱敏实战: 构建企业级敏感信息保护体系
java·spring boot·数据安全
float_六七1 小时前
Java Stream流:从入门到精通
java·windows·python