什么是悲观锁和乐观锁?两者的区别和应用场景有哪些

来源:建站技术作者:深圳网站建设头衔:草根站长
导读:本期聚焦于小伙伴创作的《什么是悲观锁和乐观锁?两者的区别和应用场景有哪些》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《什么是悲观锁和乐观锁?两者的区别和应用场景有哪些》有用,将其分享出去将是对创作者最好的鼓励。

在并发编程和数据库操作场景中,多个线程或事务同时操作同一份数据时,很容易出现数据不一致的问题,悲观锁和乐观锁就是用来解决这类并发冲突的两种核心思路,二者的设计理念和适用场景有非常明显的区别。

什么是悲观锁和乐观锁?两者的区别和应用场景有哪些

悲观锁的核心概念与实现

悲观锁的核心假设是:在数据处理过程中,大概率会出现其他事务或线程来竞争修改同一份数据,因此会在操作数据前就先加锁,确保自己操作期间其他竞争者无法修改数据。

数据库层面的悲观锁实现

在关系型数据库中,最常用的悲观锁实现是SELECT ... FOR UPDATE语句,该语句会对查询到的行加上排他锁,其他事务想要对这些行执行修改或者加锁操作都会被阻塞,直到当前事务提交释放锁。

下面是一个MySQL中使用悲观锁的示例:

-- 开启事务
START TRANSACTION;
-- 查询id为1的用户余额并加悲观锁
SELECT balance FROM user_account WHERE id = 1 FOR UPDATE;
-- 执行业务逻辑,比如扣除100元
UPDATE user_account SET balance = balance - 100 WHERE id = 1;
-- 提交事务,释放锁
COMMIT;

Java中的悲观锁实现

在Java并发编程中,synchronized关键字和ReentrantLock都是典型的悲观锁实现,会在获取资源前先尝试获取锁,获取不到就会进入阻塞状态。

以下是synchronized的使用示例:

public class PessimisticLockDemo {
    private static final Object lock = new Object();
    private static int count = 0;

    public static void increment() {
        // 加悲观锁,同一时间只有一个线程能执行同步块内的逻辑
        synchronized (lock) {
            count++;
        }
    }
}

乐观锁的核心概念与实现

乐观锁的核心假设是:在数据处理过程中,大概率不会有其他事务或线程来竞争修改同一份数据,因此不会提前加锁,而是在更新数据时判断这段时间内有没有其他操作者修改过数据,如果有就放弃本次操作或者重试。

数据库层面的乐观锁实现

数据库中最常用的乐观锁实现是版本号机制,也就是给数据表增加一个版本号字段,每次更新数据时版本号加1,更新时同时校验版本号是否和查询时的一致。

下面是版本号机制的实现示例:

-- 查询数据时获取当前版本号
SELECT id, balance, version FROM user_account WHERE id = 1;
-- 假设查询到的version是5,更新时校验版本号,同时版本号加1
UPDATE user_account 
SET balance = balance - 100, version = version + 1 
WHERE id = 1 AND version = 5;
-- 如果受影响行数为0,说明版本号已经被修改,更新失败

Java中的乐观锁实现

Java中AtomicInteger等原子类就是基于乐观锁的CAS(Compare And Swap)机制实现的,会在更新值时比较当前值和预期值是否一致,一致才更新成功。

以下是AtomicInteger的使用示例:

import java.util.concurrent.atomic.AtomicInteger;

public class OptimisticLockDemo {
    private static AtomicInteger count = new AtomicInteger(0);

    public static void increment() {
        // CAS操作,预期值是当前值,更新为新值
        int current;
        do {
            current = count.get();
        } while (!count.compareAndSet(current, current + 1));
    }
}

悲观锁和乐观锁的核心区别

两者的核心差异主要体现在以下几个维度:

对比维度悲观锁乐观锁
加锁时机操作数据前就加锁更新数据时才校验冲突
阻塞情况获取不到锁会阻塞等待不会阻塞,冲突时更新失败
适用场景写操作多、冲突概率高的场景读操作多、冲突概率低的场景
实现复杂度依赖数据库或语言内置锁机制,实现简单需要额外维护版本号或CAS逻辑,实现稍复杂
性能表现频繁加锁释放锁,高并发下性能较差无锁竞争,高并发下读多写少场景性能更好

两者的适用场景

适合用悲观锁的场景

  • 数据冲突概率非常高,比如库存扣减场景,同一个商品同时被大量用户下单,写操作非常频繁,用悲观锁可以避免大量的更新失败重试。
  • 业务逻辑复杂,操作数据的时间较长,提前加锁可以避免长事务带来的数据不一致问题。
  • 对数据一致性要求极高,不允许出现任何更新失败的情况,比如金融转账的核心账务处理。

适合用乐观锁的场景

  • 读操作远多于写操作,比如用户个人信息修改,大部分时间都是查询信息,很少修改,冲突概率极低。
  • 系统并发量很高,悲观锁的阻塞等待会带来大量的线程上下文切换开销,用乐观锁可以提升系统吞吐量。
  • 可以接受更新失败时让用户重试,比如用户提交表单时提示数据已被修改,请重新加载后提交。

使用时的注意事项

使用悲观锁时要注意控制加锁的范围和时间,避免长事务持有锁导致其他请求阻塞,甚至出现死锁问题。使用乐观锁时要注意ABA问题,也就是数据被修改后又改回原值,CAS机制无法识别这种情况,必要时可以结合版本号或者增加额外的状态字段来避免。另外乐观锁更新失败时需要有合理的重试机制,避免无限重试消耗系统资源。

悲观锁乐观锁数据库锁并发控制修改时间:2026-07-21 03:36:26

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。