手撕高并发双刃剑:乐观锁与悲观锁的终极对决(附场景代码)

360影视 日韩动漫 2025-04-22 00:09 6

摘要:凌晨3点的办公室,我盯着屏幕上诡异的余额数据——明明有100个并发扣款请求,账户却只扣减了87次。这个血淋淋的教训让我真正读懂了锁机制的精髓。本文将用真实案例拆解两种锁的底层实现,带你避开千万级并发场景中的深坑。

凌晨3点的办公室,我盯着屏幕上诡异的余额数据——明明有100个并发扣款请求,账户却只扣减了87次。这个血淋淋的教训让我真正读懂了锁机制的精髓。本文将用真实案例拆解两种锁的底层实现,带你避开千万级并发场景中的深坑。

数据库级:BEGIN;SELECT * FROM account WHERE id=1 FOR UPDATE; -- 加行锁UPDATE account SET balance=balance-100 WHERE id=1;COMMIT;java同步锁

java

// 悲观锁经典实现public synchronized void transfer(Long from, Long to, BigDecimal amount) { // 业务逻辑}版本号方案:UPDATE products SET stock=stock-1, version=version+1 WHERE id=1001 AND version=3; -- 版本号校验CAS原子操作

java

AtomicInteger atomicInt = new AtomicInteger(5);atomicInt.compareAndSet(5, 10); // 核心CAS操作

悲观锁方案

java

@Transactionalpublic boolean deductStock(Long itemId) { // 1. 查询并加锁 Item item = itemMapper.selectForUpdate(itemId); // 2. 校验库存 if(item.getStock

乐观锁方案

java

public boolean deductStock(Long itemId) { while(true) { // 1. 获取当前版本 Item item = itemMapper.selectById(itemId); // 2. 校验库存 if(item.getStock 0) return true; }}ABA问题(数据被改回原值)

java

// 解决方案:增加时间戳版本号AtomicStampedReference atomicRef = new AtomicStampedReference(0, 0);自旋消耗CPU(高并发场景循环重试代价大)版本号竞争激烈导致成功率下降

来源:大龄程序猿小武

相关推荐