java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring Boot高并发锁

详解解Spring Boot高并发锁的使用方法

作者:蹦跑的蜗牛

在高并发场景中,多个线程/用户会同时操作同一共享资源,如果不做控制,会导致数据错误,锁是解决这类问题的核心工具之一,下面就来介绍一下Spring Boot高并发锁的使用

在高并发场景中(比如电商秒杀、抢票系统、转账交易),多个线程/用户会同时操作同一共享资源(如库存、账户余额、订单号)。如果不做控制,会导致数据错误(如库存超卖、余额负数)、业务逻辑混乱(如重复下单)。锁(Lock)是解决这类问题的核心工具之一。

一、概述:为什么高并发下需要锁?

1. 高并发的“数据竞争”问题

当多个线程同时修改同一个共享资源时(如数据库的库存字段、内存中的缓存值),如果没有控制,会出现“数据不一致”。例如:

2. 锁的核心作用

锁是一种“互斥机制”,保证同一时刻只有一个线程能操作共享资源,避免数据竞争。类比现实中的“公共卫生间”:锁门后,其他人必须等待,直到当前用户释放锁(开门)。

二、锁的类型与适用场景

在Spring Boot中,常用的锁分为3类,需根据业务场景选择:

锁类型实现方式适用场景优点缺点
JVM内置锁synchronized关键字单体应用(单进程)的小范围并发代码简单,JVM自动管理锁无法跨进程(分布式场景无效)
JUC显式锁ReentrantLock(Lock接口)单体应用需要灵活控制锁(如超时、可中断)支持超时、可中断、公平锁需要手动释放锁(否则死锁)
分布式锁Redis(Redisson)、ZooKeeper分布式系统(多进程/多服务器)的并发跨进程协调,全局唯一依赖外部组件(如Redis),有性能开销

三、锁的具体使用与代码实现

场景说明:模拟“电商库存扣减”

需求:用户下单时扣减商品库存,要求高并发下库存不能超卖(库存≥0)。
假设商品ID为1001,初始库存10件。

1. JVM内置锁:synchronized

适用于单体应用(只有1个Spring Boot实例),代码简单,JVM自动加锁/释放。

@Service
public class StockService {
    // 模拟数据库中的库存(实际开发中用数据库或缓存)
    private int stock = 10;

    // 下单扣减库存(synchronized保证同一时刻只有1个线程执行)
    public synchronized boolean deductStock(int productId, int count) {
        // 检查库存是否足够
        if (stock < count) {
            return false; // 库存不足
        }
        // 模拟业务耗时(如查询数据库、记录日志)
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        // 扣减库存
        stock -= count;
        System.out.println("扣减成功,剩余库存:" + stock);
        return true;
    }
}

关键说明

2. JUC显式锁:ReentrantLock

适用于单体应用,但需要更灵活的锁控制(如设置超时、可中断)。

@Service
public class StockService {
    private int stock = 10;
    // 显式锁(可重入锁,支持公平/非公平)
    private final ReentrantLock lock = new ReentrantLock();

    public boolean deductStock(int productId, int count) {
        // 尝试加锁(最多等待2秒,避免死锁)
        try {
            if (lock.tryLock(2, TimeUnit.SECONDS)) {
                if (stock >= count) {
                    Thread.sleep(100); // 模拟业务耗时
                    stock -= count;
                    System.out.println("扣减成功,剩余库存:" + stock);
                    return true;
                } else {
                    System.out.println("库存不足");
                    return false;
                }
            } else {
                System.out.println("获取锁超时");
                return false;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        } finally {
            // 必须在finally中释放锁(避免异常导致锁未释放)
            lock.unlock();
        }
    }
}

关键说明

3. 分布式锁:Redisson(基于Redis)

适用于分布式系统(多个Spring Boot实例部署),解决跨进程的并发问题。

@Service
public class StockService {
    @Autowired
    private RedissonClient redissonClient;

    // 模拟数据库库存(实际用数据库或缓存,如Redis存储库存)
    private int stock = 10;

    public boolean deductStock(int productId, int count) {
        // 定义锁的名称(按商品ID隔离,不同商品用不同锁)
        String lockKey = "lock:product:" + productId;
        RLock lock = redissonClient.getLock(lockKey);

        try {
            // 加锁(自动续期,防止业务耗时过长锁过期)
            // waitTime: 等待锁的最大时间(5秒)
            // leaseTime: 锁自动释放时间(30秒,防止死锁)
            boolean locked = lock.tryLock(5, 30, TimeUnit.SECONDS);
            if (!locked) {
                System.out.println("获取锁失败,稍后再试");
                return false;
            }

            // 检查并扣减库存
            if (stock >= count) {
                Thread.sleep(100); // 模拟业务耗时
                stock -= count;
                System.out.println("扣减成功,剩余库存:" + stock);
                return true;
            } else {
                System.out.println("库存不足");
                return false;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        } finally {
            // 释放锁(只有自己加的锁才能释放)
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}
关键说明

四、实际业务举例:电商秒杀场景

场景描述

某商品开启秒杀(库存100件),1000个用户同时点击“立即购买”,需要保证:

解决方案(分布式锁)

  1. 用户点击下单时,先通过Redisson获取该商品的分布式锁(lock:seckill:productId)。
  2. 获得锁的线程检查库存是否足够(stock > 0)。
  3. 库存足够则扣减库存,生成订单;否则返回“已售罄”。
  4. 释放锁,让其他线程继续竞争。

关键点

五、总结

1. 锁的选择原则

2. 注意事项

3. 扩展思考

到此这篇关于详解解Spring Boot高并发锁的使用方法的文章就介绍到这了,更多相关Spring Boot高并发锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

您可能感兴趣的文章:
阅读全文