用 Redis 的 List 存储库存队列,并通过 LPOP 原子性出队来保证并发安全案例

Jedis 作为 Redis 客户端库(简单易用),实现一个模拟秒杀库存扣减的案例。

Java 代码示例

java 复制代码
import redis.clients.jedis.Jedis;

public class RedisStockQueue {

    private static final String STOCK_KEY = "product:1001:stock";

    public static void main(String[] args) {
        // 连接 Redis
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        jedis.auth("your_password"); // 如果有密码

        // 初始化库存队列(假设库存 5 件)
        initStock(jedis, 5);

        // 模拟多个用户并发抢购
        for (int i = 1; i <= 10; i++) {
            String userId = "user_" + i;
            new Thread(() -> {
                String result = buyProduct(jedis, userId);
                System.out.println(userId + " -> " + result);
            }).start();
        }

        jedis.close();
    }

    /**
     * 初始化库存队列
     */
    private static void initStock(Jedis jedis, int stockCount) {
        jedis.del(STOCK_KEY); // 清空旧库存
        for (int i = 1; i <= stockCount; i++) {
            jedis.rpush(STOCK_KEY, "stock_" + i);
        }
        System.out.println("库存初始化完成,数量:" + stockCount);
    }

    /**
     * 用户抢购商品
     */
    private static String buyProduct(Jedis jedis, String userId) {
        // LPOP 原子性出队
        String stockItem = jedis.lpop(STOCK_KEY);
        if (stockItem != null) {
            return "抢购成功,获得库存:" + stockItem;
        } else {
            return "抢购失败,库存已空";
        }
    }
}

代码说明

  1. 库存初始化

    • RPUSH 将库存数据压入 Redis List,例如 stock_1stock_2...
    • List 的顺序可以代表库存的唯一标识。
  2. 抢购逻辑

    • LPOP 从队列头部取出一个库存项。
    • LPOP 是 Redis 的原子操作,即使多个线程同时执行,也不会出现超卖。
  3. 并发安全

    • Redis 的单线程模型保证了 LPOP 的原子性,不需要额外加锁。

运行效果示例

假设库存是 5 件,10 个用户同时抢购,输出可能是:

库存初始化完成,数量:5

user_1 -> 抢购成功,获得库存:stock_1

user_3 -> 抢购成功,获得库存:stock_2

user_5 -> 抢购成功,获得库存:stock_3

user_2 -> 抢购成功,获得库存:stock_4

user_4 -> 抢购成功,获得库存:stock_5

user_6 -> 抢购失败,库存已空

user_7 -> 抢购失败,库存已空

user_8 -> 抢购失败,库存已空

user_9 -> 抢购失败,库存已空

user_10 -> 抢购失败,库存已空

相关推荐
流子7 小时前
etcd安装与配置完全指南
数据库·etcd
太过平凡的小蚂蚁7 小时前
适配器模式:让不兼容的接口协同工作
java·前端·javascript
ljh_learn_from_base7 小时前
【spring boot 使用apache poi 生成和处理word 文档】
java·spring boot·word·apache
涔溪7 小时前
在 Electron 框架中实现数据库的连接、读取和写入
javascript·数据库·electron
少年攻城狮8 小时前
OceanBase系列---【如何把一个表改造成分区表?】
数据库·sql·oceanbase
l1t8 小时前
对luasql-duckdb PR的测试
c语言·数据库·单元测试·lua·duckdb
数字芯片实验室8 小时前
流片可以失败,但人心的账本不能亏空
java·开发语言
l1t8 小时前
利用DeepSeek辅助改写luadbi-duckdb支持日期和时间戳数据类型
c语言·数据库·人工智能·junit·lua·duckdb·deepseek