SpringBoot + Redis:模拟 10w 人的秒杀抢单
往期热门文章:
1、别瞎写工具类了,Spring自带的挺香的! 2、一口气说出 Redis 16 个常见使用场景 3、监控员工离职倾向系统已被下架,网友:劝你善良 4、同事说,我写Java代码像写诗 5、阿里p7和副处级干部选哪个? 来源:www.cnblogs.com/wangrudong003/p/10627539.html
Jedis的nx生成锁
如何删除锁 模拟抢单动作(10w个人开抢) jedis的nx生成锁
redis.clients
jedis
public boolean setnx(String key, String val) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
if (jedis == null) {
return false;
}
return jedis.set(key, val, "NX", "PX", 1000 * 60).
equalsIgnoreCase("ok");
} catch (Exception ex) {
} finally {
if (jedis != null) {
jedis.close();
}
}
return false;
}
NX:是否存在key,存在就不set成功 PX:key过期时间单位设置为毫秒(EX:单位秒)
@GetMapping("/setnx/{key}/{val}")
public boolean setnx(@PathVariable String key, @PathVariable String val) {
return jedisCom.setnx(key, val);
}
![](https://filescdn.proginn.com/a7a54716d032ba19d9a3a5dd66d0b66a/0dd7e966a2e2cd6d637617c14fe2920b.webp)
如何删除锁
public int delnx(String key, String val) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
if (jedis == null) {
return 0;
}
//if redis.call('get','orderkey')=='1111' then return redis.call('del','orderkey') else return 0 end
StringBuilder sbScript = new StringBuilder();
sbScript.append("if redis.call('get','").append(key).append("')").append("=='").append(val).append("'").
append(" then ").
append(" return redis.call('del','").append(key).append("')").
append(" else ").
append(" return 0").
append(" end");
return Integer.valueOf(jedis.eval(sbScript.toString()).toString());
} catch (Exception ex) {
} finally {
if (jedis != null) {
jedis.close();
}
}
return 0;
}
@GetMapping("/delnx/{key}/{val}")
public int delnx(@PathVariable String key, @PathVariable String val) {
return jedisCom.delnx(key, val);
}
模拟抢单动作(10w个人开抢)
//总库存
private long nKuCuen = 0;
//商品key名字
private String shangpingKey = "computer_key";
//获取锁的超时时间 秒
private int timeout = 30 * 1000;
@GetMapping("/qiangdan")
public Listqiangdan() {
//抢到商品的用户
ListshopUsers = new ArrayList<>();
//构造很多用户
Listusers = new ArrayList<>();
IntStream.range(0, 100000).parallel().forEach(b -> {
users.add("神牛-" + b);
});
//初始化库存
nKuCuen = 10;
//模拟开抢
users.parallelStream().forEach(b -> {
String shopUser = qiang(b);
if (!StringUtils.isEmpty(shopUser)) {
shopUsers.add(shopUser);
}
});
return shopUsers;
}
/**
* 模拟抢单动作
*
* @param b
* @return
*/
private String qiang(String b) {
//用户开抢时间
long startTime = System.currentTimeMillis();
//未抢到的情况下,30秒内继续获取锁
while ((startTime + timeout) >= System.currentTimeMillis()) {
//商品是否剩余
if (nKuCuen <= 0) {
break;
}
if (jedisCom.setnx(shangpingKey, b)) {
//用户b拿到锁
logger.info("用户{}拿到锁...", b);
try {
//商品是否剩余
if (nKuCuen <= 0) {
break;
}
//模拟生成订单耗时操作,方便查看:神牛-50 多次获取锁记录
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//抢购成功,商品递减,记录用户
nKuCuen -= 1;
//抢单成功跳出
logger.info("用户{}抢单成功跳出...所剩库存:{}", b, nKuCuen);
return b + "抢单成功,所剩库存:" + nKuCuen;
} finally {
logger.info("用户{}释放锁...", b);
//释放锁
jedisCom.delnx(shangpingKey, b);
}
} else {
//用户b没拿到锁,在超时范围内继续请求锁,不需要处理
// if (b.equals("神牛-50") || b.equals("神牛-69")) {
// logger.info("用户{}等待获取锁...", b);
// }
}
}
return "";
}
![](https://filescdn.proginn.com/9b72fd5792220dcb96e1dc9396076869/827336498f1637a0a8dc7302a09285d5.webp)
![](https://filescdn.proginn.com/312706422360d631541d57ecfe3b1391/4110d5ecb67231652d9f2883b72bdd2d.webp)
往期热门文章:
1、滴滴程序员被亲戚鄙视:年薪八十万还不如二本教书的... 2、IT界惊现文豪!华为领导及阿里P10遭吐槽
3、上海地铁乘车码“变红”,吓倒一众乘客,官方:为营造节日气氛…… 4、Spring Boot 项目打成 .exe 程序?实战来了! 5、Spring Boot太重,Vert.x真香! 6、中美程序员不完全对比 7、Spring Boot 3.0 M1 发布,正式弃用 Java 8,最低要求 Java 17。。。 8、一个“扛住100亿次请求”的春晚红包系统 9、你觉得HTTPS能防止重放攻击吗? 10、数据一致性,为什么不推荐双写?
评论