悲观锁与乐观锁

一、悲观锁( 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、数据一致性级别、重试成本等维度综合考量。

相关推荐
jackson凌1 分钟前
【Java学习笔记】键盘录入方法
java·笔记·学习
zozowind1 分钟前
1Panel快速安装Dify指南
人工智能·后端
xin4972 分钟前
Calcite 如何通过 SQL 来查询不同数据源? 有性能问题吗?
后端·源码
编程乐趣3 分钟前
MahApps.Metro:专为 WPF 应用程序设计的 UI 框架
后端
kfepiza5 分钟前
ServletRequestListener 的用法笔记250417
java·java ee
Piper蛋窝7 分钟前
Go 1.7 相比 Go 1.6 有哪些值得注意的改动?
后端·go
kfepiza7 分钟前
ServletContextListener 的用法笔记250417
java·java ee
张哈大8 分钟前
《苍穹外卖Day2:大一菜鸟的代码升空纪实》
后端
一介输生8 分钟前
Spring Cloud实现权限管理(网关+jwt版)
java·后端
AI_Infra智塔9 分钟前
ZStack文档DevOps平台建设实践
后端