悲观锁与乐观锁

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

相关推荐
宋小黑10 分钟前
JDK 6到25 全版本网盘合集 (Windows + Mac + Linux)
java·后端
念何架构之路20 分钟前
Go进阶之panic
开发语言·后端·golang
7哥♡ۣۖᝰꫛꫀꪝۣℋ22 分钟前
Spring-cloud\Eureka
java·spring·微服务·eureka
先跑起来再说23 分钟前
Git 入门到实战:一篇搞懂安装、命令、远程仓库与 IDEA 集成
ide·git·后端·elasticsearch·golang·intellij-idea
老毛肚35 分钟前
手写mybatis
java·数据库·mybatis
两点王爷37 分钟前
Java基础面试题——【Java语言特性】
java·开发语言
choke23341 分钟前
[特殊字符] Python 文件与路径操作
java·前端·javascript
choke2331 小时前
Python 基础语法精讲:数据类型、运算符与输入输出
java·linux·服务器
码农阿豪1 小时前
Flask应用上下文问题解析与解决方案:从错误日志到完美修复
后端·python·flask
岁岁种桃花儿1 小时前
CentOS7 彻底卸载所有JDK/JRE + 重新安装JDK8(实操完整版,解决kafka/jps报错)
java·开发语言·kafka