目录
[乐观锁(Optimistic Lock)](#乐观锁(Optimistic Lock))
[悲观锁(Pessimistic Lock)](#悲观锁(Pessimistic Lock))
[2.1 乐观锁的实现机制](#2.1 乐观锁的实现机制)
[2.2 悲观锁的工作原理](#2.2 悲观锁的工作原理)
[2.3 对比](#2.3 对比)
一、什么是乐观锁&悲观锁?
乐观锁(Optimistic Lock)
乐观锁是一种并发控制策略 ,它假设在大多数情况下,多个事务/线程访问同一资源时不会发生冲突,因此在操作数据时不预先加锁,而是在提交更新时才检测是否有冲突发生。
悲观锁(Pessimistic Lock)
悲观锁则假设冲突总会发生 ,因此在操作数据前必须先获取锁,确保在整个操作期间其他事务无法修改数据。
二、乐观锁&悲观锁的工作原理
2.1 乐观锁的实现机制
1.版本号机制
sql
-- 读取数据时获取版本号
SELECT id, name, version FROM products WHERE id = 1;
-- 假设返回 version = 1
-- 更新时检查版本号是否变化
UPDATE products
SET name = 'new_name', version = version + 1
WHERE id = 1 AND version = 1;
-- 如果更新行数为0,说明数据已被其他事务修改
2.CAS(Compare And Swap)
冲突检测逻辑:
读取时:获取变量的当前值 A
计算时:基于A计算出新值 B
提交时:使用CAS原子操作,检查变量是否仍为A
是 → 原子性地更新为B,操作成功
否 → 变量已被修改,操作失败
无需再加版本号,浪费内存空间
2.2 悲观锁的工作原理
代码层面的悲观锁:
java
// Java synchronized 关键字
public synchronized void updateStock(Long productId, Integer quantity) {
// 临界区代码
}
// ReentrantLock
private final ReentrantLock lock = new ReentrantLock();
public void updateStock(Long productId, Integer quantity) {
lock.lock();
try {
// 临界区代码
} finally {
lock.unlock();
}
}
2.3 对比
| 特性 | 乐观锁 | 悲观锁 |
|---|---|---|
| 加锁时机 | 提交更新时检测冲突 | 操作前先加锁 |
| 实现复杂度 | 较高,需要额外字段或机制 | 较低,依赖数据库或系统锁 |
| 并发性能 | 高(无锁开销) | 低(锁竞争导致等待) |
| 适用冲突频率 | 低冲突场景 | 高冲突场景 |
| 死锁风险 | 无死锁 | 可能发生死锁 |
| 数据一致性 | 最终一致 | 强一致 |
使用场景:
- 冲突少、读多写少 → 优先选择乐观锁
- 冲突多、写操作频繁 → 优先选择悲观锁
- 强一致性要求 → 选择悲观锁
- 高并发、高性能要求 → 选择乐观锁
