用 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 "抢购失败,库存已空";
}
}
}
代码说明
-
库存初始化
- 用
RPUSH将库存数据压入 Redis List,例如stock_1、stock_2... - List 的顺序可以代表库存的唯一标识。
- 用
-
抢购逻辑
- 用
LPOP从队列头部取出一个库存项。 LPOP是 Redis 的原子操作,即使多个线程同时执行,也不会出现超卖。
- 用
-
并发安全
- Redis 的单线程模型保证了
LPOP的原子性,不需要额外加锁。
- Redis 的单线程模型保证了
运行效果示例
假设库存是 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 -> 抢购失败,库存已空