什么是乐观锁?原理、实现方式与实战详解

在高并发系统中,如何保证数据一致性,又尽量提升系统性能,是一个绕不开的话题。乐观锁正是在这种背景下被广泛使用的一种并发控制机制。本文将从概念、原理、实现方式、应用场景和实战案例等方面,带你系统理解什么是乐观锁。


文章目录

一、什么是乐观锁?

1. 乐观锁的定义

乐观锁(Optimistic Lock),是一种对并发冲突持"乐观态度"的锁机制。

它的核心思想是:

认为并发冲突发生的概率较低,操作时不加锁,提交时再校验。

如果发现数据被修改过,就重试或失败处理。


2. 通俗理解

乐观锁可以理解为:

  • "先干活,后检查"
  • "出问题再重来"

就像写文档时:

先编辑,保存时提示冲突再处理。

不会一开始就锁住文件。


二、乐观锁的工作原理

乐观锁的一般执行流程:

  1. 读取数据
  2. 记录版本号/状态值
  3. 修改数据
  4. 提交时校验版本
  5. 校验成功则更新,否则失败重试

示意流程:

本质上:

通过校验机制,而不是阻塞机制保证一致性。


三、乐观锁的主要实现方式

1. 基于版本号(Version)实现

这是最常见的乐观锁方案。

数据库表结构示例:

sql 复制代码
ALTER TABLE product ADD version INT;

更新时校验版本:

sql 复制代码
UPDATE product
SET stock = stock - 1, version = version + 1
WHERE id = 1 AND version = 3;

特点:

  • 只有版本匹配才会更新成功
  • 否则返回 0 行受影响
  • 调用方决定是否重试

2. 基于时间戳实现

使用时间字段判断数据是否被修改。

示例:

sql 复制代码
WHERE id = 1 AND update_time = '2026-02-14 10:00:00'

本质与版本号类似,但精度依赖时间戳。


3. CAS(Compare And Swap)机制

在 Java 并发包中,大量使用 CAS 实现乐观锁。

示例:

java 复制代码
AtomicInteger count = new AtomicInteger(0);
count.compareAndSet(0, 1);

CAS 逻辑:

如果当前值等于期望值,则更新,否则失败。


四、乐观锁 vs 悲观锁

理解乐观锁,必须和悲观锁对比来看。

对比维度 乐观锁 悲观锁
并发态度 乐观 悲观
是否加锁
冲突处理 重试 阻塞
性能 稳定
适合场景 读多写少 写多冲突多

一句话总结:

冲突少用乐观锁,冲突多用悲观锁。


五、乐观锁的典型使用场景

1. 读多写少系统

例如:

  • 商品信息查询
  • 配置中心
  • 用户资料

读远大于写,冲突概率低。


2. 高并发但低冲突场景

例如:

  • 抢优惠券
  • 抽奖系统
  • 秒杀预减库存

适合乐观锁提升吞吐量。


3. 分布式系统

在微服务环境中,加锁成本高,乐观锁更常用。


六、实战案例:库存扣减

1. 不安全写法

java 复制代码
stock = stock - 1;

可能导致超卖。


2. 基于版本号的乐观锁实现

sql 复制代码
UPDATE goods
SET stock = stock - 1,
    version = version + 1
WHERE id = 1 AND version = #{version};

Java 伪代码:

java 复制代码
while (true) {
    Goods goods = query();
    boolean success = update(goods);
    if (success) break;
}

失败则重试。


七、乐观锁的优缺点分析

优点

  • 并发性能高
  • 无阻塞
  • 吞吐量大
  • 适合分布式系统

缺点

  • 实现复杂
  • 重试成本高
  • 冲突多时性能下降
  • 可能出现 ABA 问题

八、使用乐观锁的注意事项

1. 控制重试次数

避免无限重试导致 CPU 飙高。

建议设置最大重试次数。


2. 防止 ABA 问题

ABA:值变了又变回原值。

解决方案:

  • 加版本号
  • 使用带时间戳的标记

3. 结合业务降级处理

多次失败时:

  • 返回失败
  • 排队处理
  • 转人工

避免系统雪崩。


九、面试常见问题

1. 什么是乐观锁?

答:

不加锁,通过版本校验保证一致性。


2. 乐观锁适合什么场景?

答:

读多写少、冲突少场景。


3. CAS 和乐观锁关系?

答:

CAS 是乐观锁的底层实现方式之一。


参考

Java并发常见面试题总结(中)

相关推荐
华仔啊8 小时前
为啥不用 MP 的 saveOrUpdateBatch?MySQL 一条 SQL 批量增改才是最优解
java·后端
xiaoye201810 小时前
Lettuce连接模型、命令执行、Pipeline 浅析
java
beata13 小时前
Java基础-18:Java开发中的常用设计模式:深入解析与实战应用
java·后端
Seven9714 小时前
剑指offer-81、⼆叉搜索树的最近公共祖先
java
雨中飘荡的记忆1 天前
保证金系统入门到实战
java·后端
Nyarlathotep01131 天前
Java内存模型
java
暮色妖娆丶1 天前
不过是吃了几年互联网红利罢了,我高估了自己
java·后端·面试
NE_STOP2 天前
MyBatis-参数处理与查询结果映射
java
狂奔小菜鸡2 天前
Day40 | Java中的ReadWriteLock读写锁
java·后端·java ee