悲观锁与乐观锁

一、悲观锁( Pessimistic Lock

定义与核心思想

悲观锁基于"数据并发必然冲突"的假设,在访问共享资源前强制加锁,确保独占访问。其核心是"先加锁,后操作"的保守策略。

实现方式

1. Java层面

  • synchronized关键字(重量级锁实现)

  • ReentrantLock等显式锁

2. 数据库层面

  • SELECT FOR UPDATE(行级/表级锁)

  • 共享锁(S锁)、排他锁(X锁)

特点与优劣势

优势

  1. 安全性极高,严格保证数据一致性

  2. 适合临界区执行时间长的场景

劣势

1.锁开销大(用户态/内核态切换)

2.可能引起线程阻塞、优先级反转

3.死锁风险

二、乐观锁(Optimistic Lock)

定义与核心思想

乐观锁基于"数据冲突概率低"的假设,采用"先操作,后验证"的开放策略,通过版本控制实现无锁化并发。

实现方式

1. 版本号机制

数据表增加version字段,更新时校验版本[4][15][18]

2. CAS (Compare And Swap

  • 原子操作包含三个参数:内存值V、预期值A、新值B

  • 仅在V==A时更新为B,否则重试

  • Java实现:AtomicInteger等原子类

特点与优劣势

优势

  1. 无锁设计提升吞吐量

  2. 避免线程上下文切换

  3. 适合读多写少场景

劣势

  1. ABA问题(需版本号辅助解决)

  2. 高竞争场景导致频繁重试

  3. 需业务层处理冲突

三、关键差异对比

维度 悲观锁 乐观锁
并发假设 必定冲突 大概率无冲突
锁机制 显式加锁 无锁(版本控制)
冲突处理 预防冲突 检测并解决冲突
适用场景 写操作多、临界区耗时长 读操作多、临界区执行快
实现复杂度 简单(JVM/DB原生支持) 需业务层处理冲突逻辑
典型应用 银行转账、库存扣减 点赞计数、配置更新
性能表现 高安全但吞吐量低 高吞吐但存在重试开销

四、架构选型建议

  1. 优先考虑乐观锁

    • 当系统读占比超过70%

    • 业务能容忍短暂数据不一致(如缓存更新)

    • 需支持高并发(如电商秒杀库存校验)

  2. 必须使用悲观锁

    • 强事务一致性要求(如金融交易)

    • 临界区包含复杂计算(避免重复执行)

    • 无法处理重试的场景(如实时竞价系统)

  3. 混合使用策略

    • 例如JUC中的StampedLock,先尝试乐观读,冲突时升级为悲观锁

五、典型案例

  1. 悲观锁
java 复制代码
// 使用ReentrantLock转账
   public void transfer(Account from, Account to, int amount) {
       lock.lock();
       try {
           from.withdraw(amount);
           to.deposit(amount);
       } finally {
           lock.unlock();
       }
   }
  1. 乐观锁
java 复制代码
// 使用AtomicReference实现计数器
   AtomicInteger counter = new AtomicInteger(0);
   public void safeIncrement() {
       int oldValue;
       do {
           oldValue = counter.get();
       } while (!counter.compareAndSet(oldValue, oldValue + 1));
   }

在分布式系统中,可结合Redis的WATCH/MULTI命令实现乐观锁,或通过数据库的版本号字段实现多版本并发控制(MVCC)。实际架构设计中,需结合QPS、数据一致性级别、重试成本等维度综合考量。

相关推荐
Penge6666 小时前
Elasticsearch BKD 树与 PointRangeQuery:为何数值查询会有性能瓶颈
后端
木木一直在哭泣6 小时前
【收藏级】Java Stream.reduce 全面解析:从零到通透(原理图 + 实战 + 最佳实践)
后端
Penge6666 小时前
Elasticsearch Filter 缓存:Bitset 如何让查询速度飙升
后端
用户84913717547166 小时前
ThreadLocal 源码深度解析:JDK 设计者的“妥协”与“智慧”
java·后端
木木一直在哭泣6 小时前
Java Stream.filter 全面解析:定义、原理与最常见使用场景
后端
用户0304805912636 小时前
# 【Maven避坑】源码去哪了?一文看懂 Maven 工程与打包后的目录映射关系
java·后端
绫语宁7 小时前
以防你不知道LLM小技巧!为什么 LLM 不适合多任务推理?
人工智能·后端
v***55347 小时前
springboot使用logback自定义日志
java·spring boot·logback
qq_336313937 小时前
java基础-集合进阶
java·开发语言·windows
稚辉君.MCA_P8_Java7 小时前
Gemini永久会员 归并排序(Merge Sort) 基于分治思想(Divide and Conquer)的高效排序算法
java·linux·算法·spring·排序算法